Frontend - NextJS

How to Create a NavLink in Next.js 15 (App Router) with Tailwind

Learn how to build a reusable NavLink component in Next.js 15 (App Router) using Tailwind CSS. We'll use `next/link`, the `usePathname` hook to highlight active links, and the `cn` function

Screenshot of NavLink component in Next.js with Tailwind styling

When building navigation in modern Next.js (15 with the App Router), it's often useful to have a reusable NavLink component. A NavLink not only renders links with Tailwind CSS but also highlights the active route based on the current URL.

Why NavLink?

By default, Next.js provides the `Link` component for navigation:

Navlink.tsx
import Link from "next/link";

export default function Example() {
  return <Link href="/about">About</Link>;
}

However, it doesn’t tell you if the link is currently active. That’s where NavLink comes in: it compares the current path (using the `usePathname` hook) with the link’s href and applies styling conditionally.

Key Ingredients

  • `Link` from `next/link` for navigation
  • `usePathname` from `next/navigation` to get the current path
  • `cn` function (className utility) to conditionally merge Tailwind classes
  • Tailwind CSS for styling
  • TypeScript and TSX for type-safe components

How It Works

The NavLink component is a client component (using the `\"use client\"` directive).

Navlink.tsx
"use client";

import Link, { LinkProps } from "next/link";
import { usePathname } from "next/navigation";
import { cn } from "@/lib/utils";

interface NavLinkProps extends LinkProps {
  children: React.ReactNode;
  className?: string;
}

export function NavLink({ href, children, className }: NavLinkProps) {
  const pathname = usePathname();
  const isActive = pathname === href;

  return (
    <Link
      href={href}
      className={cn(
        "transition-colors hover:text-black",
        isActive ? "text-blue-600 font-semibold" : "text-gray-500",
        className
      )}
    >
      {children}
    </Link>
  );
}


Inside it, `usePathname()` provides the current route. If that matches the link’s href, we apply an `active` style (like bold text, underline, or a different color). The `cn` function makes managing these conditional Tailwind classes clean and readable.

Styling with Tailwind

Tailwind makes it easy to toggle classes for active and inactive states. For example, you might use `text-gray-500 hover:text-black` for inactive links and `text-blue-600 font-semibold` for the active one.

globals.css
// Active link
"text-blue-600 font-semibold"

// Inactive link
"text-gray-500 hover:text-black"

Using NavLink

Now, navigation becomes super simple:

Navbar.tsx
import { NavLink } from "@/components/NavLink";

export default function Navbar() {
  return (
    <nav className="flex gap-4">
      <NavLink href="/">Home</NavLink>
      <NavLink href="/about">About</NavLink>
      <NavLink href="/contact">Contact</NavLink>
    </nav>
  );
}

Final Thoughts

With a simple NavLink component:

  • Your navigation is reusable
  • It’s type-safe with TSX
  • Styled cleanly with Tailwind
  • Fully compatible with the Next.js App Router

A small detail like highlighting the current page dramatically improves the user experience.