How to style Link component when on active page on Next.js
Asked Answered
C

4

12

I have a question about styling an anchor component when it is on the active page.

Here is my code:

import Link from 'next/link';
import styled from 'styled-components';

const NavStyle = styled.nav`
    display: flex;
    justify-content: space-between;
    .nav-link a {
        text-decoration: none;
        color: white;
        padding: 10px;
        background-color: #FFCF00;
    }
`;

export default function Nav() {
    return (
        <NavStyle>
            <div className="nav-link">
                <Link href="/" passHref>
                    <a>HOME</a>
                </Link>
                <Link href="/pricing">
                    <a>PRICING</a>
                </Link>
                <Link href="/terms">
                    <a>TERMS</a>
                </Link>
                <Link href="/login">
                    <a>LOGIN</a>
                </Link>
            </div>
            <Link href="/">
                <a>LOGO</a>
            </Link>
        </NavStyle>
    )
}

What I want is, when the I click on the link and move to another page, the active link (that's matched with the URL) would have a green background. I have tried this, but it doesn't make any change:

const NavStyle = styled.nav`
    display: flex;
    justify-content: space-between;
    .nav-link a {
        text-decoration: none;
        color: white;
        padding: 10px;
        background-color: #FFCF00;
        &[aria-current] {
          background-color: green;
       }
    }
`;
Coconut answered 5/2, 2021 at 10:33 Comment(0)
F
9

Next.js won't add aria-current to your active link; however, you can create a custom Link component that checks if the current pathname is the same as the href prop.

import React from "react";
import Link from "next/link";
import { useRouter } from "next/router";

const NavLink = ({ children, href }) => {
  const child = React.Children.only(children);
  const router = useRouter();

  return (
    <Link href={href}>
      {React.cloneElement(child, {
        "aria-current": router.pathname === href ? "page" : null
      })}
    </Link>
  );
};

export default NavLink;

Then, you can use this component instead of the default Link whenever you want to add aria-current to the active link:

const NavStyle = styled.nav`
  display: flex;
  justify-content: space-between;

  a {
    background-color: #353637;
    color: #fff;
    padding: 1rem;
    text-decoration: none;

    &[aria-current] {
      background-color: #faf9f4;
      color: #353637;
    }
  }
`;

export default function Nav() {
  return (
    <NavStyle>
      <div className="nav-link">
        <NavLink href="/">
          <a>HOME</a>
        </NavLink>
        <NavLink href="/pricing">
          <a>PRICING</a>
        </NavLink>
        <NavLink href="/terms">
          <a>TERMS</a>
        </NavLink>
        <NavLink href="/login">
          <a>LOGIN</a>
        </NavLink>
      </div>
      <Link href="/">
        <a>LOGO</a>
      </Link>
    </NavStyle>
  );
}
Frum answered 5/2, 2021 at 14:46 Comment(0)
A
1

In case some one is using MaterialUI is easy to use a wrapper Box

router comes from const router = useRouter(); that is part of next/router

<Box 
   sx={{
       '& a':{
             color: router.pathname === '/' ? '#757de8' : 'rgba(0, 0, 0, 0.87)'
          }
      }}>
  <Link href={'/'}> HOME </Link>
</Box>
Arola answered 8/3, 2023 at 2:15 Comment(0)
B
0

The best answer to this question that I have found is at https://amanexplains.com/using-aria-current-for-nav-links/

Note that the first answer to this question says to use pathname, but the link I provided describes why that won't work in some cases (slugged paths, for instance). Instead, use asPath.

Note also that this currently (NextJS 13) only works for client-side components as far as I can tell.

Bruckner answered 31/12, 2022 at 0:25 Comment(0)
I
0

This is how I am doing it in my project with Material Ui

  export default function MainAppBar(props: Props) {
    const theme = useTheme();
    const {navItems} = props
    const pathname = usePathname()

  .... rest of code

  return (

        {navItems && <Box sx={{ display: { xs: "none", sm: "block" } }}>
          {navItems.map((item, index) => (
            <Link
              key={index}
              href={item["href"]}
              passHref
            >
              <Button
                sx={{ color: pathname === item["href"] ? '#ff7' : 'inherit' }}>
                {item["text"]}
              </Button>
            </Link>
          ))}
        </Box>
        }

    ....
     );
   }

then I pass links as prop

export const LINKS: { text: string, href: string, icon: JSX.Element }[] = [
    { text: "Home", href: "/", icon: <Home /> },
    { text: "Work", href: "/work", icon: <Star /> },
    { text: "Blogs", href: "/blog", icon: <Checklist /> },
    { text: "Typography", href: "/typography", icon: <Checklist /> },
];

Usage:

    <MainAppBar  navItems={LINKS} />

Result:

enter image description here

Impound answered 19/12, 2023 at 20:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.