I love Next.js, its speed, simplicity, tooling but one thing I hate about Next.js is its lack of a native active link component. Before Next.js, I was using create-react-app and react-router for most of my personal projects but once I switched over to Next.js one of my biggest pain point is that I have to pretty much write my own NavLink component every single time for every new project I made. There are a couple of tutorials and Stackoverflows on how to exactly solve this problem but none of them actually achieves the simplicity react-router offers out fo the box.
In react-router when you want to make use of an active link all you do is import the nav-link component and pass it an activeClassName
prop and voila it works. Just like this:
<NavLink activeClassName='is-active' to='/about'>About</NavLink>
Most of tutorials on how to implement the ActiveLink api looks like this
// adapted from https://stackoverflow.com/questions/53262263/target-active-link-when-the-route-is-active-in-next-js
import { useRouter } from 'next/router'
import PropTypes from 'prop-types'
import Link from 'next/link'
import React, { Children } from 'react'
const ActiveLink = ({ children, activeClassName, ...props }) => {
const { asPath } = useRouter()
const child = Children.only(children)
const childClassName = child.props.className || ''
const className =
asPath === props.href || asPath === props.as
? `${childClassName} ${activeClassName}`.trim()
: childClassName
return (
<Link {...props}>
{React.cloneElement(child, {
className: className || null,
})}
</Link>
)
}
export default ActiveLink
The only issue with this API is that, it still acts like the normal Next.js link component which requires you to implement a link tag() as the child of the link component. But what if you are not using a library like ChakraUI. The implementation in Chakra looks like this:
import { Link as ChakraLink, LinkProps, useColorModeValue } from '@chakra-ui/react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import React from 'react'
interface NavLinkProps extends LinkProps {
children?: string | React.ReactNode
to: string
activeProps?: LinkProps
_hover?: LinkProps
}
function NavLink({ to, activeProps, children, _hover, ...props }: NavLinkProps) {
const router = useRouter()
const isActive = router.pathname === to
const color = useColorModeValue('black', 'selected')
if (isActive) {
return (
<Link href={to}>
<ChakraLink
fontWeight='bold'
{...props}
{...activeProps}
_hover={{ color: 'selected' }}
color={color}>
{children}
</ChakraLink>
</Link>
)
}
return (
<Link href={to}>
<ChakraLink {...props} _hover={{ color: 'selected' }}>
{children}
</ChakraLink>
</Link>
)
}
export default NavLink
And to use it:
<NavLink mr={4} to='/dashboard'>
Dashboard
</NavLink>
<NavLink mr={4} to='/dashboard' activeProps={{fontWeight:'bold'}}>
Dashboard
</NavLink>
Top comments (3)
There's a prop called
_activeLink
that you can use if you are using theNavLink
component from React Router or Remix package. Basically it will work with any routing package or logic that adds the.active
class to the active link.This is the perfect solution to keep the Nextjs link functionality. Thank you very much for this!
Thank you, I actually had this issue some weeks ago.