Openstatus www.openstatus.dev

๐Ÿ“ article breadcrumb (#984)

authored by

Thibault Le Ouay and committed by
GitHub
bacc4c66 a5808088

+224
apps/web/public/assets/posts/dynamic-breadcrumb-nextjs/breadcrumb.png

This is a binary file and will not be displayed.

+224
apps/web/src/content/posts/dynamic-breadcrumb-nextjs.mdx
··· 1 + --- 2 + title: Dynamic Breadcrumb in Next.js with Parallel Routes 3 + description: 4 + Learn how to create a dynamic breadcrumb in Next.js with parallel routes. 5 + author: 6 + name: Thibault Le Ouay Ducasse 7 + url: https://twitter.com/thibaultleouay 8 + publishedAt: 2024-08-19 9 + image: /assets/posts/dynamic-breadcrumb-nextjs/breadcrumb.png 10 + --- 11 + 12 + In this post, we'll dive into the process of creating dynamic breadcrumbs in Next.js using parallel routes. Our goal is to build a breadcrumb component that automatically updates based on the current page and its hierarchy, all while leveraging server-side rendering for optimal performance. 13 + 14 + ## Introduction 15 + 16 + Breadcrumbs are an essential navigation aid in web applications, helping users understand their current location within a site's hierarchy. With Next.js 13's introduction of parallel routes, we have new tools to create more dynamic and flexible navigation structures. 17 + 18 + 19 + You can find the complete, working example for this tutorial on [GitHub](https://github.com/openstatusHQ/nextjs-dynamic-breadcrumb/). The project uses Next.js 15 and demonstrates the implementation of parallel routes alongside our dynamic breadcrumb. 20 + 21 + 22 + ## The Challenge 23 + 24 + We're building a website that showcases a catalog of dogs and cats. Our primary challenge is to create a breadcrumb that adapts to the user's current location within the site structure. 25 + 26 + ### Project Structure 27 + 28 + Our repository is organized as follows: 29 + 30 + 31 + ``` 32 + src/ 33 + app/ 34 + about/ 35 + page.tsx 36 + cats/ 37 + page.tsx 38 + [id]/ 39 + page.tsx 40 + dogs/ 41 + page.tsx 42 + [id]/ 43 + page.tsx 44 + ``` 45 + 46 + 47 + ### Desired Breadcrumb Behavior 48 + 49 + 50 + 1. On the homepage: 51 + 52 + `Home` 53 + 54 + 2. On pet pages (e.g., Dogs or Cats): 55 + 56 + `Home > Dogs` or `Home > Cats` 57 + 58 + 3. On individual pet pages: 59 + 60 + Here we only have the pet id, so we need to fetch the pet name from the server side and display it in the breadcrumb. 61 + 62 + `Home > Dogs > Dog Name` 63 + 64 + The key is to fetch the necessary data on the server side and dynamically update the breadcrumb based on the current route instead of displaying the pet id. 65 + 66 + 67 + 68 + ### Parallel route ๐Ÿš€ 69 + 70 + [Parallel routes](https://nextjs.org/docs/app/building-your-application/routing/parallel-routes) in Next.js allow us to render multiple pages in the same layout simultaneously. This feature is particularly useful for our breadcrumb implementation as it allows us to maintain a consistent navigation structure across different page types. 71 + 72 + 73 + #### Homepage 74 + 75 + In our root layout we will use slot to render the breadcrumb component. 76 + 77 + ```tsx 78 + export default function RootLayout({ 79 + breadcrumb, 80 + children, 81 + }: Readonly<{ 82 + breadcrumb: React.ReactNode; 83 + children: React.ReactNode; 84 + }>) { 85 + return ( 86 + <html lang="en"> 87 + <body> 88 + {breadcrumb} 89 + {children} 90 + </body> 91 + </html> 92 + ); 93 + } 94 + ``` 95 + 96 + We need to create a new folder `@breadcrumb` in the `app` folder 97 + 98 + Here we create a new file `page.tsx` that will be responsible for rendering the breadcrumb. 99 + 100 + ```tsx 101 + import { 102 + Breadcrumb, 103 + BreadcrumbItem, 104 + BreadcrumbLink, 105 + BreadcrumbList, 106 + } from "@/components/ui/breadcrumb"; 107 + 108 + export default function BreadcrumbSlot() { 109 + return ( 110 + <Breadcrumb> 111 + <BreadcrumbList> 112 + <BreadcrumbItem> 113 + <BreadcrumbLink href="/">Home</BreadcrumbLink> 114 + </BreadcrumbItem> 115 + </BreadcrumbList> 116 + </Breadcrumb> 117 + ); 118 + } 119 + ``` 120 + 121 + #### Pet pages 122 + 123 + We also want to create a catch all components for the dynamic routes in the `app` folder, to achieve this we need to create a new file `page.tsx` in the `@breadcrumb/[...all]` folder. 124 + 125 + ```tsx 126 + import { 127 + Breadcrumb, 128 + BreadcrumbItem, 129 + BreadcrumbLink, 130 + BreadcrumbList, 131 + BreadcrumbPage, 132 + BreadcrumbSeparator, 133 + } from "@/components/ui/breadcrumb"; 134 + import React from "react"; 135 + import type { ReactElement } from "react"; 136 + 137 + export default function BreadcrumbSlot({ 138 + params, 139 + }: { params: { all: string[] } }) { 140 + const breadcrumbItems: ReactElement[] = []; 141 + let breadcrumbPage: ReactElement = <></>; 142 + for (let i = 0; i < params.all.length; i++) { 143 + const route = params.all[i]; 144 + const href = `/${params.all.at(0)}/${route}`; 145 + if (i === params.all.length - 1) { 146 + breadcrumbPage = ( 147 + <BreadcrumbItem> 148 + <BreadcrumbPage className="capitalize">{route}</BreadcrumbPage> 149 + </BreadcrumbItem> 150 + ); 151 + } else { 152 + breadcrumbItems.push( 153 + <React.Fragment key={href}> 154 + <BreadcrumbItem> 155 + <BreadcrumbLink href={href} className="capitalize"> 156 + {route} 157 + </BreadcrumbLink> 158 + </BreadcrumbItem> 159 + </React.Fragment>, 160 + ); 161 + } 162 + } 163 + 164 + return ( 165 + <Breadcrumb> 166 + <BreadcrumbList> 167 + <BreadcrumbItem> 168 + <BreadcrumbLink href="/">Home</BreadcrumbLink> 169 + </BreadcrumbItem> 170 + {breadcrumbItems} 171 + <BreadcrumbSeparator /> 172 + {breadcrumbPage} 173 + </BreadcrumbList> 174 + </Breadcrumb> 175 + ); 176 + } 177 + ``` 178 + This code was taken from the [Jeremy's post](https://jeremykreutzbender.com/blog/app-router-dynamic-breadcrumbs) about dynamic breadcrumbs in Next.js. 179 + 180 + #### Dogs and Cats pages 181 + 182 + We need to create a new file `page.tsx` in the `@breadcrumb/dogs/[id]` folder, we must follow the exact same structure as our specific pet pages. 183 + In this component we will fetch the pet name from the server side and display it in the breadcrumb. 184 + 185 + ```tsx 186 + 187 + import { 188 + BreadcrumbItem, 189 + BreadcrumbLink, 190 + BreadcrumbList, 191 + BreadcrumbPage, 192 + BreadcrumbSeparator, 193 + } from "@/components/ui/breadcrumb"; 194 + 195 + export default async function BreadcrumbSlot({params}: {params: {id: string}}) { 196 + // Fetch our cat information from the database 197 + const cat = await fetchCat({id: params.id}); 198 + 199 + return ( 200 + <BreadcrumbList> 201 + <BreadcrumbItem> 202 + <BreadcrumbLink href="/">Home</BreadcrumbLink> 203 + </BreadcrumbItem> 204 + <BreadcrumbSeparator /> 205 + <BreadcrumbItem> 206 + <BreadcrumbLink href="/cats">Cats</BreadcrumbLink> 207 + </BreadcrumbItem> 208 + <BreadcrumbSeparator /> 209 + <BreadcrumbItem> 210 + <BreadcrumbPage className="capitalize">{cat.name}</BreadcrumbPage> 211 + </BreadcrumbItem> 212 + </BreadcrumbList> 213 + ); 214 + } 215 + ``` 216 + 217 + 218 + ## Conclusion 219 + 220 + By leveraging Next.js parallel routes and server-side rendering, we've created a dynamic breadcrumb component that updates based on the current route and fetches data efficiently on the server side. This approach provides a smooth user experience while maintaining good performance. 221 + 222 + Remember to check out the full working example on [GitHub](https://github.com/openstatusHQ/nextjs-dynamic-breadcrumb/) to see how all the pieces fit together in a Next.js 15 project. 223 + 224 + Happy coding!