How to Add Active Link Styles with Nextjs

December 13, 2021 (3y ago)

As a frontend developer, I love to make things that are a delight to the user. Subtle little details that make the page pop or give the webpage personality, things that make other developers go "nice".

So, I knew for my blog I wanted to have some active link styling on my navigation bar. The styling would not only give the page some character but would also improve the user experience.

My blog is built using Nextjs and styled-components at the time of writing this. Which meant that it wasn't as simple as using the pseudo-class :active and applying styles to it when the link was in the :active state.

The reason it wasn't straightforward is the Nextjs <Link> component doesn't know what the current route is, so it can never hold an active state.

We can use the next/router to solve this problem.

Unfortunately, you cannot use the <Link> component from Nextjs by itself to add active styling. Therefore, you need to use the useRouter hook which is part of the next/router component. The useRouter hook allows magically lets you access the router object inside any component. This is how we are going to tell our application which page (route) the user is on, so we can then tell the link to apply active styles.

The best solution in my opinion is to create a custom <ActiveLink> component, link the one below:

import { useRouter } from "next/router";
import styled from "styled-components";

const StyledLink = styled.a`
  color: ${({ href, path }) => (href === path ? "red" : "black")};
`;

function ActiveLink({ children, href }) {
  const router = useRouter();

  const handleClick = (e) => {
    e.preventDefault();
    router.push(href);
  };

  return (
    <StyledLink href={href} onClick={handleClick} currentPath={router.asPath}>
      {children}
    </StyledLink>
  );
}

export default ActiveLink;

I like this solution for a few reasons, so let's go through it step by step.

The first thing is we don't lose the benefits that come from the <Link> component because we use the push method. This method handles the client-side transitions, meaning it is faster and doesn't trigger a full refresh. Which results in better performance and experience for the user. It also improves those tasty lighthouse scores.

Next, we use the asPath method. This method returns the path (or route) as shown in the browser address bar meaning we can conditionally check this against the href we pass as an argument to the <ActiveLink> component.

The result is it prevents us from needing to hardcode the paths on a parent element and we can handle the active state at the link level. This allows you to use the ActiveLink component in other components when ever you want to apply :active styling.

To actually apply the active link styles, we pass the StyledLink two key props. The first is the href, the actual link we want next to route to. The second is currentPath, which is the route that is currently in the browser.

Now, using styled-components we can check if the href and the currentPath components match using a ternary. If they match we apply the active styles in this case red font otherwise we apply black font.

Now you can detect if a link is active using Nextjs, you can start making your links delight users. If you're interested in how I made the links in my blog, sign up to my newsletter to be one of the first to get access to my article on SVG styling.

If you're set on using the <Link> component Flavio has some solutions here.