Back to Blog Page
Frontend Development

Next.js Highlight Current Page Link – How to Highlight the Active Link in Next.js

Next.js Highlight Current Page Link – How to Highlight the Active Link in Next.js

Written by Kolade Chris | Aug 17, 2024 | #Next.js #WebDev | 7 minute Read

Creating a user-friendly navigation system is essential for any website, and highlighting the current page link in the navbar is an integral aspect of that.

In Next.js, a popular React framework, implementing this feature can improve user experience by visually indicating the current page or section the user is visiting. This not only guides users through your site content, it also adds a touch of elegance to the website design.

There are many ways you can highlight the active navlink in Next.jsand React. The popular way of doing it with React is using the react-router package. In Next JS, we used to do it with the userRouter hook.

This article will take you through the new Next JS way of highlighting the active navlink, particularly in Next 14, and that’s using the usePathname hook.

The Navbar we are Working with

The navbar we are using for this guide has already been prepared for you with Tailwind CSS. You can expand the code to see it in full.

1
'use client';
2
import { useState } from 'react';
3
import Link from 'next/link';
4
5
const Navbar = () => {
6
const [isOpen, setIsOpen] = useState(false);
7
133 collapsed lines
8
const toggleMenu = () => {
9
setIsOpen(!isOpen);
10
};
11
12
const handleClick = () => {
13
setIsOpen(false);
14
};
15
16
return (
17
<nav className="bg-green-700">
18
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 lg:py-3">
19
<div className="flex items-center justify-between h-16">
20
<div className="flex-shrink-0">
21
<Link href="/">
22
<span className="text-white font-bold text-3xl">Green World</span>
23
</Link>
24
</div>
25
<div className="hidden md:flex">
26
<div className="flex items-baseline space-x-4 w-full justify-between">
27
<Link
28
href="/"
29
className="
30
text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2
31
rounded-md text-2xl font-medium"
32
>
33
Home
34
</Link>
35
<Link
36
href="/about"
37
className="
38
text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2 rounded-md
39
text-2xl font-medium"
40
>
41
About
42
</Link>
43
<Link
44
href="/services"
45
className="
46
text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2 rounded-md
47
text-2xl font-medium"
48
>
49
Services
50
</Link>
51
<Link
52
href="/contact"
53
className="
54
text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2 rounded-md
55
text-2xl font-medium"
56
>
57
Contact
58
</Link>
59
</div>
60
</div>
61
<div className="-mr-2 flex md:hidden">
62
<button
63
type="button"
64
className="inline-flex items-center justify-center p-2 rounded-md text-white
65
hover:text-gray-100 hover:bg-green-900 focus:outline-none
66
focus:bg-green-900 focus:text-white transition duration-150 ease-in-out"
67
onClick={toggleMenu}
68
aria-label="Main menu"
69
aria-expanded={isOpen}
70
>
71
<svg
72
className="block h-6 w-6"
73
stroke="currentColor"
74
fill="none"
75
viewBox="0 0 24 24"
76
>
77
{isOpen ? (
78
<path
79
strokeLinecap="round"
80
strokeLinejoin="round"
81
strokeWidth="2"
82
d="M6 18L18 6M6 6l12 12"
83
/>
84
) : (
85
<path
86
strokeLinecap="round"
87
strokeLinejoin="round"
88
strokeWidth="2"
89
d="M4 6h16M4 12h16M4 18h16"
90
/>
91
)}
92
</svg>
93
</button>
94
</div>
95
</div>
96
</div>
97
98
{/* Mobile menu */}
99
<div className={`${isOpen ? 'block' : 'hidden'} md:hidden `}>
100
<div
101
className={`${
102
isOpen ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'
103
} px-2 pt-2 pb-3 space-y-1 sm:px-3 `}
104
>
105
<Link
106
href="/"
107
className=" text-white hover:bg-green-900 hover:text-gray-100 block
108
px-3 py-2 rounded-md text-base font-medium"
109
onClick={handleClick}
110
>
111
Home
112
</Link>
113
<Link
114
href="/about"
115
className="text-white hover:bg-green-900 hover:text-gray-100 block
116
px-3 py-2 rounded-md text-base font-medium"
117
onClick={handleClick}
118
>
119
About
120
</Link>
121
<Link
122
href="/services"
123
className="text-white hover:bg-green-900 hover:text-gray-100
124
block px-3 py-2 rounded-md text-base font-medium"
125
onClick={handleClick}
126
>
127
Services
128
</Link>
129
<Link
130
href="/contact"
131
className=" text-white hover:bg-green-900 hover:text-gray-100
132
block px-3 py-2 rounded-md text-base font-medium"
133
onClick={handleClick}
134
>
135
Contact
136
</Link>
137
</div>
138
</div>
139
</nav>
140
);
141
};
142
143
export default Navbar;

What’s the code above doing?

  • the use-client directive signifies to React that the component is a client component
  • useState is imported from React and Link from next link
  • an isOpen state variable is set and setIsOpen to modify the state
  • a toggleMenu function is created to handle the opening and closing of the mobile menu
  • an handleClick function is created to hide and show the nav items when one of them is selected on the mobile menu

This is what the navbar looks like on a desktop screen:

First desktop navbar

And this is what it looks like on a mobile screen:

First mobile navbar

Step 1: Create a new Next JS app with the command below

Terminal window
1
npx create-next-app@latest # if you're using NPM
2
yarn create next-app # if you're using Yarn
3
pnpm create next-app # if you're using PNPM

Step 2: Create a Navbar.jsx component in the root and import the usePathname hook from next/navigation

1
'use client';
2
import { useState } from 'react';
3
4
import Link from 'next/link';
5
import { usePathname } from 'next/navigation';
6
7
const Navbar = () => {
8
const [isOpen, setIsOpen] = useState(false);
9
10
const toggleMenu = () => {
11
setIsOpen(!isOpen);
12
};
13
14
const handleClick = () => {
15
setIsOpen(false);
16
};
17
18
return (
19
<nav className="bg-green-700">{/* Rest of desktop and mobile menu */}</nav>
20
);
21
};
22
23
export default Navbar;

Step 3: Then you must initialize the usePathname hook

1
'use client';
2
import { useState } from 'react';
3
4
import Link from 'next/link';
5
import { usePathname } from 'next/navigation';
6
7
const Navbar = () => {
8
const [isOpen, setIsOpen] = useState(false);
9
10
const toggleMenu = () => {
11
setIsOpen(!isOpen);
12
};
13
14
const handleClick = () => {
15
setIsOpen(false);
16
};
17
18
const pathname = usePathname();
19
20
return (
21
<nav className="bg-green-700">{/* Rest of desktop and mobile menu */}</nav>
22
);
23
};
24
25
export default Navbar;
1
className={`${pathname === '/pageFolderName ? 'bg-green-900' : ''}
2
text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2 rounded-md text-2xl font-medium`}

For example, the entire services page link and text will now look like this:

1
<Link
2
href="/services"
3
className={`${
4
pathname === '/services' ? 'bg-green-900' : ''
5
} text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2 rounded-md text-2xl font-medium`}
6
>
7
Services
8
</Link>

And those of the about page will look like this:

1
<Link
2
href="/about"
3
className={`${
4
pathname === '/about' ? 'bg-green-900' : ''
5
} text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2 rounded-md text-2xl font-medium`}
6
>
7
About
8
</Link>

You must also make the classNames of the mobile items dynamic. For example, this is what the about page item of the mobile menu will look like:

1
<Link
2
href="/about"
3
className={`${
4
pathname === '/about' ? 'bg-green-900' : ''
5
} text-white hover:bg-green-900 hover:text-gray-100 block px-3 py-2
6
rounded-md text-base font-medium`}
7
onClick={handleClick}
8
>
9
About
10
</Link>

After making all the necessary changes, the entire Navbar component should be this:

1
'use client';
2
import { useState } from 'react';
3
4
import Link from 'next/link';
5
import { usePathname } from 'next/navigation';
6
7
const Navbar = () => {
133 collapsed lines
8
const [isOpen, setIsOpen] = useState(false);
9
10
const toggleMenu = () => {
11
setIsOpen(!isOpen);
12
};
13
14
const handleClick = () => {
15
setIsOpen(false);
16
};
17
18
const pathname = usePathname();
19
20
return (
21
<nav className="bg-green-700">
22
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 lg:py-3">
23
<div className="flex items-center justify-between h-16">
24
<div className="flex-shrink-0">
25
<Link href="/">
26
<span className="text-white font-bold text-3xl">Green World</span>
27
</Link>
28
</div>
29
<div className="hidden md:flex">
30
<div className="flex items-baseline space-x-4 w-full justify-between">
31
<Link
32
href="/"
33
className={`${
34
pathname === '/' ? 'bg-green-900' : ''
35
} text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2
36
rounded-md text-2xl font-medium`}
37
>
38
Home
39
</Link>
40
<Link
41
href="/about"
42
className={`${
43
pathname === '/about' ? 'bg-green-900' : ''
44
} text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2
45
rounded-md text-2xl font-medium`}
46
>
47
About
48
</Link>
49
<Link
50
href="/services"
51
className={`${
52
pathname === '/services' ? 'bg-green-900' : ''
53
} text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2
54
rounded-md text-2xl font-medium`}
55
>
56
Services
57
</Link>
58
<Link
59
href="/contact"
60
className={`${
61
pathname === '/contact' ? 'bg-green-900' : ''
62
} text-white hover:bg-green-900 hover:text-gray-100 px-3 py-2
63
rounded-md text-2xl font-medium`}
64
>
65
Contact
66
</Link>
67
</div>
68
</div>
69
<div className="-mr-2 flex md:hidden">
70
<button
71
type="button"
72
className="inline-flex items-center justify-center
73
p-2 rounded-md text-white hover:text-gray-100 hover:bg-green-900
74
focus:outline-none focus:bg-green-900 focus:text-white transition duration-150
75
ease-in-out"
76
onClick={toggleMenu}
77
aria-label="Main menu"
78
aria-expanded={isOpen}
79
>
80
<svg
81
className="block h-6 w-6"
82
stroke="currentColor"
83
fill="none"
84
viewBox="0 0 24 24"
85
>
86
{isOpen ? (
87
<path
88
strokeLinecap="round"
89
strokeLinejoin="round"
90
strokeWidth="2"
91
d="M6 18L18 6M6 6l12 12"
92
/>
93
) : (
94
<path
95
strokeLinecap="round"
96
strokeLinejoin="round"
97
strokeWidth="2"
98
d="M4 6h16M4 12h16M4 18h16"
99
/>
100
)}
101
</svg>
102
</button>
103
</div>
104
</div>
105
</div>
106
107
{/* Mobile menu */}
108
<div className={`${isOpen ? 'block' : 'hidden'} md:hidden `}>
109
<div
110
className={`${
111
isOpen ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'
112
} px-2 pt-2 pb-3 space-y-1 sm:px-3 `}
113
>
114
<Link
115
href="/"
116
className={`${
117
pathname === '/' ? 'bg-green-900' : ''
118
} text-white hover:bg-green-900 hover:text-gray-100 block px-3 py-2
119
rounded-md text-base font-medium`}
120
onClick={handleClick}
121
>
122
Home
123
</Link>
124
<Link
125
href="/about"
126
className={`${
127
pathname === '/about' ? 'bg-green-900' : ''
128
} text-white hover:bg-green-900 hover:text-gray-100 block px-3 py-2
129
rounded-md text-base font-medium`}
130
onClick={handleClick}
131
>
132
About
133
</Link>
134
<Link
135
href="/services"
136
className={`${
137
pathname === '/services' ? 'bg-green-900' : ''
138
} text-white hover:bg-green-900 hover:text-gray-100
139
block px-3 py-2 rounded-md text-base font-medium`}
140
onClick={handleClick}
141
>
142
Services
143
</Link>
144
<Link
145
href="/contact"
146
className={`${
147
pathname === '/contact' ? 'bg-green-900' : ''
148
} text-white hover:bg-green-900 hover:text-gray-100
149
block px-3 py-2 rounded-md text-base font-medium`}
150
onClick={handleClick}
151
>
152
Contact
153
</Link>
154
</div>
155
</div>
156
</nav>
157
);
158
};
159
160
export default Navbar;

Don’t forget to expand the code so you can see the changes I made.

Step 5: You then need to import the Navbar component into your layout file and use it.

1
import '@/assets/styles/globals.css';
2
import Navbar from '@/components/Navbar';
3
4
export const metadata = {
5
title: 'Green World | Home of Nature Scenes',
6
description: 'Find the coolest nature images and videos',
7
keywords: 'nature animals trees fields',
8
};
9
10
const MainLayout = ({ children }: React.PropsWithChildren<{}>) => {
11
return (
12
<html>
13
<body>
14
<Navbar />
15
<main>{children}</main>
16
</body>
17
</html>
18
);
19
};
20
21
export default MainLayout;

The navbar should now look like this on a desktop screen:

Final desktop navbar

And it should look like this on a mobile screen:

Final desktop navbar

If you’re wondering how I got an item to show for each page, I created each page in the app directory. This is what the folder structure looks like:

Project folder structure

Wrapping Up

Highlighting the current page link in the navbar is one of the many critical features you should consider implementing if you have user experience in mind.

This feature not only enhances the user experience, it also strengthens visual design and sends to the user a good perception of your website.

To better understand things, you can grab the code for this article from the project GitHub repo.