32

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?

Youssouf Oumar
  • 29,373
  • 11
  • 46
  • 65
Mahesh Bansod
  • 1,493
  • 2
  • 24
  • 42
  • 1
    you can use [`usePathname`](https://beta.nextjs.org/docs/api-reference/use-pathname) but it doesn't work with server components yet – mocherfaoui Nov 26 '22 at 18:11

4 Answers4

43

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 thread.

Youssouf Oumar
  • 29,373
  • 11
  • 46
  • 65
8

If you are looking to get the current active pathname on the server side component/page/layout, you can use headers from next/headers.

import { headers } from "next/headers";

export function Component() {
  const headersList = headers();
  const activePath = headersList.get("x-invoke-path");
  // const activeUrl = headersList.get("referer");
  // const activeHost = headersList.get("host");
  
  return (<div>{activePath}</div>)
}
Tanmoy Bhowmick
  • 1,305
  • 15
  • 20
0

Here is how I do it through the server side:

export const POST = (request: Request) => {
  const pathname = new URL(request.url).pathname;
  return new Response(`You requested from ${pathname}`, { status: 200 });
};
0

One way (albeit a bit hacky) to get the pathname on the server side which doesn't require middleware is answered here:

Nextjs13 app dir doesn't have a nice API for this yet. It'll be nice if the props passed down the segment.

For now, you can use children.props.childProp.segment to get the path of your route on the server.

loqusion
  • 1
  • 2