Next.js Discord

Discord Forum

Get pathname on 404 pages (server component)?

Unanswered
English Setter posted this in #help-forum
Open in Discord
English SetterOP
Is there a way to get the "not found" pathname on a server side 404 page

The constraint is statically generated catch all route export const dynamic = 'force-static'

I tried a workaround to put the pathname in a custom header in the middleware, but the force-static strips the headers at runtime

The use case being a smarter 404 with more context and CTAs than an "oops"

Thank you very much!

13 Replies

English SetterOP
I want it to be a server component for some filesystem access
@English Setter I want it to be a server component for some filesystem access
American Crow
Split in two components and import the stuff that needs client interaction
not-found.tsx (server)
import NotFoundClient from "@/app/not-found-client";

export default function Custom404() {
   return (
      <div className="flex flex-col items-center justify-center h-screen">
         <h1 className="text-4xl font-bold">404 - Page Not Found</h1>
         <NotFoundClient />
         <p className="text-lg">Sorry, the page you are looking for does not exist.</p>
      </div>
   )
}


not-found-client.tsx (client)
"use client"
import { usePathname } from "next/navigation";

export default function NotFoundClient() {
    const path = usePathname()
    return (
        <h2 className="text-lg font-bold tracking-tight"> Path &quot;{path}&quot; is not valid </h2>
    )
}
English SetterOP
Thanks for the suggestion @American Crow , but I need the pathname to generate a sidebar that has to be a server component for fs access

I'm not sure if a client component can render a server component? 🤔
American Crow
a sidebar in a 404 ? or is this a separate use case
@English Setter Thanks for the suggestion <@240974567730970625> , but I need the pathname to generate a sidebar that has to be a server component for fs access I'm not sure if a client component can render a server component? 🤔
American Crow
I dont know what you try to achieve exactly within the sidebar. If you just want to do for example active links. You can do something like this:

sidebar (server)
import SidebarLink from "@/app/sidebar/sidebar-link"

// Server
export default function Sidebar() {
   return (
      <div className="flex bg-orange-300 h-24 items-center px-4 space-x-8">
         <SidebarLink href="/">Home</SidebarLink>
         <SidebarLink href="/1">1</SidebarLink>
         <SidebarLink href="/2">2</SidebarLink>
         <SidebarLink href="/sidebar">3</SidebarLink>
      </div>
   )
}

sidebar-links (client)
"use client"
import { cn } from "@/lib/utils";
import Link from "next/link";
import { usePathname } from "next/navigation";

export default function SidebarLink({href, children}) {
    const path = usePathname()
    const linkIsActive = path === href  


    return (
        <Link href={href} className={cn("px-4 py-2", linkIsActive ? "bg-blue-300" : "bg-blue-100")}> {children} </Link>
    )
}
English SetterOP
I'm in a situation where the SidebarLinks themselves are built from reading a directory of mdx files @American Crow
@English Setter I'm in a situation where the `SidebarLink`s themselves are built from reading a directory of mdx files <@240974567730970625>
American Crow
Which you read server side, no? Can you not just load them in the Server Sidebar map through them and create a SidebarLink for each? Sorry if a don't understand the use case
English SetterOP
Sorry my explanation wasn't very clear, I tried to simplify.

We have different kinds of sidebars for different paths, so the server kinda needs to be aware of the pathname

I tried to workaround it, but in the I keep coming back to "I need a server side usePathname()"
American Crow
Yea there is no direct server side usePathname(). Best you can do is look at athe file directory and if its a dynamic segment read the {params}. So combosing it by hand kind of
@English Setter Sorry my explanation wasn't very clear, I tried to simplify. We have different kinds of sidebars for different paths, so the server kinda needs to be aware of the pathname I tried to workaround it, but in the I keep coming back to "I need a server side `usePathname()`"
American Crow
Btw this would still work with the approach from above:

import SidebarLink from "@/app/sidebar/sidebar-link"

const fakeMdxPaths = [
   {
      id: 1,
      path: "/apple",
   },
   {
      id: 2,
      path: "/banana",
   },
   {
      id: 3,
      path: "/cherry",
   },
]

// Server
export default function SidebarLoader() {
   // Load path from mdx file
   const mdxPath = fakeMdxPaths[0]

   let SidebarComponent = DefaultSidebar

   if (mdxPath.path.startsWith("/a")) {
      SidebarComponent = AppleSidebar
   } else if (mdxPath.path.startsWith("/b")) {
      SidebarComponent = BananaSidebar
   }

   return <SidebarComponent />
}

export function DefaultSidebar() {
   return (
      <div className="bg-gray-300">
         <SidebarLink href="/apple">Apple</SidebarLink>
         <SidebarLink href="/banana">Banana</SidebarLink>
         <SidebarLink href="/cherry">Cherry</SidebarLink>
      </div>
   )
}

export function AppleSidebar() {
   return (
      <div className="bg-red-500">
         <SidebarLink href="/apple">Apple</SidebarLink>
         <SidebarLink href="/sidebar">Sidebar</SidebarLink>
         <SidebarLink href="/cherry">Cherry</SidebarLink>
      </div>
   )
}

export function BananaSidebar() {
   return (
      <div className="bg-yellow-300">
         <SidebarLink href="/apple">Apple</SidebarLink>
      </div>
   )
}


Last try i'll shut up now 😆 :box_cat_hide:
English SetterOP
I really appreciate the effort, but my use case is much more complicated, and I also need some breadcrumbs to be generated server side