5

How to target the active Link in Next.js (next 13)

const Sidebar = () => {
  const link = [
    {
      label: ' Home',
      path: '/',
    },
    {
      label: ' About',
      path: '/about',
    }
  ]
  return (
    <div>
      {sidebarLink.map((link, index) =>
        <Link
          key={link.index}
          href={link.path}>
        </Link>
      )}
    </div>
  )
}

export default Sidebar

I tried everything to no avail

Bumhan Yu
  • 2,078
  • 1
  • 10
  • 20
majid
  • 51
  • 1
  • 4
  • 3
    Please add more details about what you want, and what you have tried so far. Also, a reproducible minimal example is recommended so that we can help you better. – Abdulrahman Ali Feb 27 '23 at 19:20
  • Check the [official docs page](https://nextjs.org/docs/api-reference/next/link) for `next/link` component. Unless you're building your own custom `` component, you'd need a child inside it (e.g. `{link.label}`). For `activeClassName` example, see Next.js [demo repo](https://github.com/vercel/next.js/tree/canary/examples/active-class-name/components) for "Active className on Link" on GitHub. – Bumhan Yu Feb 27 '23 at 19:31
  • Active link in the sidebar... For example, the color of the link should be red in the active state – majid Feb 27 '23 at 19:32
  • The GitHub method is outdated and not compatible with Next 13 – majid Feb 27 '23 at 19:34
  • Next 13 was released in October 2022, and the commit date on the `active-class-name` behavior example is November 30, 2022, whose [commit message reads](https://github.com/vercel/next.js/pull/43581) "updated the `active-class-name` example to stop using the legacy behavior". I would start there first. – Bumhan Yu Feb 27 '23 at 20:32
  • As @AbdulrahmanAli noted, please include what you tried to do as a code example, so that the community could understand what you've attempted to do so far. – Bumhan Yu Feb 27 '23 at 20:33

5 Answers5

4

Not really ideal but this is what I am doing.

"use client"; // if you are planing to use it in the component which is not marker with use client directive this is a must

import Link, { LinkProps } from "next/link";
import { usePathname } from "next/navigation"; // usePathname is a hook now imported from navigation

const ActiveLink = ({
  children,
  ...rest
 }: { children: React.ReactNode } & LinkProps) => {
   const { href } = rest;
   const pathName = usePathname();

   const isActive = pathName === href;
     return (
    // you get a global isActive class name, it is better than 
    // nothing, but it means you do not have scoping ability in 
    // certain cases
       <Link {...rest} className={isActive ? "active" : ""}> 
         {children}
       </Link>
   );
  };

export default ActiveLink;
Nikola Mitic
  • 1,298
  • 3
  • 11
  • 23
1

Official code from official docs: Nextjs check-active-links

Use usePathname and check with the link.href

'use client'
 
import { usePathname } from 'next/navigation'
import { Link } from 'next/link'
 
export function Navigation({ navLinks }) {
  const pathname = usePathname()
 
  return (
    <>
      {navLinks.map((link) => {
        const isActive = pathname.startsWith(link.href)
 
        return (
          <Link
            className={isActive ? 'text-blue' : 'text-black'}
            href={link.href}
            key={link.name}
          >
            {link.name}
          </Link>
        )
      })}
    </>
  )
}

For detailed example refer: https://stackoverflow.com/a/76660587/13431819

krishnaacharyaa
  • 14,953
  • 4
  • 49
  • 88
0
export const routes: ILink[] = [
   {
    href: '/',
    label: 'Home',
    targetSegment: null,
  },
  {
    href: '/profile',
    label: 'Profile',
    targetSegment: 'profile',
  },
];
import { useSelectedLayoutSegment } from 'next/navigation';

interface IMenuProps {
  links: Array<ILink>;
}

const Menu: FC<IMenuProps> = ({ links, title }) => {
   const activeSegment = useSelectedLayoutSegment();

   return(
     {(links || []).map(({ href, label, targetSegment }) => (
       <div className={`flex gap-1 ${activeSegment === targetSegment ? 'text- 
       custom-cyan-600' : ''}`}>...</div>
     )}
    )
}
import { routes } from '@/constants';

<DropdownMenu links={routes} />
0

The best solution I'm familiar with is using the "Layout Segment" in Next.js.

It's important to note that it also works seamlessly with i18n routes – for example: /en/about/ and so on.

I highly recommend giving it a try:)

'use client'

import { items } from '@/utils/nav'
/* example
export const items = [
    {
      id: 1,
      title: 'Home',
      href: '/',
      activeSegment: null,
    },
     {
      id: 2,
      title: 'About',
      href: '/about',
      activeSegment: 'about',
    },
    ...
  ]
*/

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

...

// Inside you client component
const activeSegment = useSelectedLayoutSegment()

....

<nav>
  {items.map((item) => (
    <Link
      key={item.id}
      href={item.href}
      className={activeSegment === item.activeSegment ? 'text-primary font-semibold' : 'text-muted-foreground'}
    >
      {item.title}
    </Link>
  ))}
</nav>

...

For further details, see the official docs

0

use a Client Component hook called "useSelectedLayoutSegments()"

import { useSelectedLayoutSegment } from 'next/navigation'

const segment = useSelectedLayoutSegment()

read more about this next.js documentation https://nextjs.org/docs/app/api-reference/functions/use-selected-layout-segment

Bisrat
  • 21
  • 4