Description
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
-
Add a thin wrapper around NavLink. Here's a codesanbox by @benoitgrelard.
-
If you're using Tailwind, use the NavLink's aria-current attribute:
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.