javascriptreactjstypescriptnext.js

How to get the current pathname in the app directory of Next.js?


I'm using the experimental app folder in Next.js 13, where they have replaced next/router with next/navigation, so I imported the useRouter hook accordingly. I do not see the property pathname in the router, which does exist in next/router's router.

Property 'pathname' does not exist on type 'AppRouterInstance'

My use case is to highlight the link in my navbar that the user is currently on. This is what I tried:


import Link from "next/link";
import { useRouter } from 'next/navigation';


const StyledNavLink: React.FC<NavLinkProps> = ({ to, children }) => {
  const router = useRouter();
  ...
  return (
    <Link href={to} className={getNavLinkClass({isActive: router.pathname === to})}>
      {children}
    </Link>
  );
};

Is there anything I can do to get the current path name or something else to add my classes to the active link?


Solution

  • When using the app router (directory), the pathname has its hook called usePathname. Here is a quote from the doc:

    The usePathname hook allows you to read the current URL pathname from a Client Component.

    Find below an example, and notice the 'use client' at the top:

    'use client';
    
    import { usePathname } from 'next/navigation';
    
    export default function Page() {
      const pathname = usePathname();
      return <div>{pathname}</div>;
    }
    

    As of now, the doc doesn’t mention a way to get the pathname server side. However, you could use the technique inspired by this GitHub comment, combining Next.js middleware and request headers:

    // middleware.js
    
    import { NextResponse } from "next/server";
    
    export function middleware(request) {
      const requestHeaders = new Headers(request.headers);
      requestHeaders.set("x-pathname", request.nextUrl.pathname);
    
      return NextResponse.next({
        request: {
          headers: requestHeaders,
        },
      });
    }
    
    // app/page.js
    
    import { headers } from "next/headers";
    
    export default async function Page() {
      const headersList = headers();
    
      return <div>{headersList.get("x-pathname")}</div>;
    }
    

    And if you are using Dynamic Routes (aka the [id] folders), and you want to know the value of the slug, check out this post.