Skip to content

NavLink breaks className and styles DOM API #6471

Open
@andrecasal

Description

@andrecasal

What version of Remix are you using?

1.16.1

Are all your remix dependencies & dev-dependencies using the same version?

  • Yes

Steps to Reproduce

The NavLink component accepts both a string and a function in its className and style attributes. This is a convenient API to quickly set up navigation-aware styles. However, this violates the DOM API that only accepts a string and you might get in trouble when using composition, for example.

Here's an example of when you might get in trouble using (Epic Stack recommended) Radix UI's NavigationMenu component and composing it with Remix's NavLink:

const MenuItem = ({ to, children }: { to: string; children?: ReactNode) => (
	<NavigationMenu.Item>
		<NavigationMenu.Link asChild>
			<NavLink to={to} className={({isActive}) => `${isActive ? 'active-classes' : 'inactive-classes'} other-classes`}>
				{children}
			</NavLink>
		</NavigationMenu.Link>
	</NavigationMenu.Item>
)

Because Radix expects className to be a string, it will render class="({ isActive }) => `${isActive ? "active-classes" : "inactive-classes"} other-classes` active" onto the DOM instead of class="active-classes other-classes.

Solutions

const MenuItem = ({ to, children }: { to: string; children?: ReactNode) => (
	<NavigationMenu.Item>
		<NavigationMenu.Link asChild>
			<NavLink to={to} className="aria-[current]:underline">
				{children}
			</NavLink>
		</NavigationMenu.Link>
	</NavigationMenu.Item>
)

Suggestions

Add a note to the documentation that the NavLink breaks the DOM API standard and provide these workarounds 👆 to fix it.

Related issues:
#1966
radix-ui/primitives#1158
radix-ui/primitives#2157

Expected Behavior

Expected documentation to note this.

Actual Behavior

Function is printed onto the DOM.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions