Detect the active link in Next.js

By

Learn how to highlight the active link in Next.js 16 with usePathname in the App Router, plus a short Pages Router alternative using useRouter.

~~~

One useful detail in a nav is knowing which URL is current, so you can style the active link differently from the others.

This is especially handy in a site header.

The Next.js Link component from next/link does not mark the active route for you. You compare the current path to each item’s href and set a class yourself.

In Next.js 16 the default is the App Router. Use usePathname from next/navigation.

If you still have a pages/ app, skip to the Pages Router section.

App Router

usePathname returns the current pathname. Compare it to each link:

'use client'

import Link from 'next/link'
import { usePathname } from 'next/navigation'

const menu = [
  { title: 'Home', path: '/home' },
  { title: 'Explore', path: '/explore' },
  { title: 'Notifications', path: '/notifications' },
]

export default function Sidebar() {
  const pathname = usePathname()

  return (
    <div>
      {menu.map((item) => {
        const isActive = pathname === item.path

        return (
          <Link
            key={item.path}
            href={item.path}
            className={
              isActive
                ? 'cursor-pointer text-blue-500'
                : 'cursor-pointer hover:bg-gray-900 hover:text-blue-500'
            }
          >
            {item.title}
          </Link>
        )
      })}
    </div>
  )
}

This component uses a hook, so it needs 'use client' at the top.

Link renders its own <a>, so className goes on Link directly. You do not need a nested <a> like older examples did.

I’d recommend this as it’s the simplest thing you can do.

If many places need the same active styles, you can also wrap Link in a small helper:

'use client'

import Link from 'next/link'
import { usePathname } from 'next/navigation'

export default function NavLink({ href, children }) {
  const pathname = usePathname()
  const isActive = pathname === href

  return (
    <Link
      href={href}
      className={isActive ? 'text-blue-500' : 'hover:text-blue-500'}
    >
      {children}
    </Link>
  )
}
import NavLink from '@/components/NavLink'

<NavLink href="/blog">Blog</NavLink>
<NavLink href="/about">About</NavLink>

For how Link wires pages together, see Linking two pages in Next.js.

Pages Router

In a pages/ app, import useRouter from next/router and read router.pathname:

import Link from 'next/link'
import { useRouter } from 'next/router'

const menu = [
  { title: 'Home', path: '/home' },
  { title: 'Explore', path: '/explore' },
  { title: 'Notifications', path: '/notifications' },
]

export default function Sidebar() {
  const router = useRouter()

  return (
    <div>
      {menu.map((item) => (
        <Link
          key={item.path}
          href={item.path}
          className={
            router.pathname === item.path
              ? 'cursor-pointer text-blue-500'
              : 'cursor-pointer hover:bg-gray-900 hover:text-blue-500'
          }
        >
          {item.title}
        </Link>
      ))}
    </div>
  )
}

Same idea: compare the current path to href, then set the class.

Here too className goes on Link, because since Next.js 13 Link renders the <a> itself. If you nest an <a> inside it, Next.js throws an “Invalid <Link> with <a> child” error, unless you add the legacyBehavior prop. That prop still exists in Next.js 16, but it is deprecated and will be removed, so don’t write new code with it.

One thing to keep in mind: router.pathname is the route pattern, for example /blog/[slug], not the URL in the address bar. For a static menu like this one that’s what you want. If you need the real URL, use router.asPath.

Tagged: Next.js · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about next: