React Breadcrumb Examples — Separators, Links, Ellipsis
Copy-paste React Breadcrumb patterns — default chevron, custom separator, Next.js Link integration, collapsed ellipsis, and dynamic pathname rendering.
A breadcrumb answers two questions at once: where am I, and how do I get back up one level? That is why the pattern survives in documentation sites, e-commerce catalogs, file browsers, settings trees, and any admin panel deeper than two levels. It looks simple enough to hand-roll, and most teams do — then rediscover the details one bug at a time: semantic list markup, separator consistency, aria-current on the final segment, graceful wrapping on a narrow phone.
Drivn's Breadcrumb settles those details in one file with zero runtime UI dependencies. The root renders a <nav aria-label="Breadcrumb"> wrapping an <ol>, and separators are injected between siblings during render, so you write items rather than dividers. Every piece hangs off the root through dot notation: Breadcrumb.Item for a link, Breadcrumb.Page for the current segment, Breadcrumb.Separator when you want to place one by hand, and Breadcrumb.Ellipsis for a collapsed middle.
Below are five patterns worth copying: the default chevron trail for a fixed-depth docs page, a slash-separated trail for settings hierarchies, a next/link swap that gives every breadcrumb client-side routing, an ellipsis that keeps deep paths on one line, and a trail computed from the live pathname. Install first via the CLI; for the engineering tradeoffs against shadcn/ui, read Drivn vs shadcn/ui Breadcrumb.
Default chevron separator
The default breadcrumb uses a ChevronRight icon between every item and renders the final segment as a non-interactive <Breadcrumb.Page>. You write only the items and the current page — separators are injected automatically between siblings at render time, so a three-level breadcrumb has three JSX children, not five.
The root applies flex items-center gap-1.5 flex-wrap text-sm text-muted-foreground so the trail wraps gracefully on narrow viewports. Each Breadcrumb.Item becomes a muted link that darkens on hover via hover:text-foreground; the current page gets font-medium text-foreground so it reads as the anchor of the trail. Use this pattern anywhere you have a clean, fixed-depth hierarchy — docs pages, admin sections, or content categories.
1 import { Breadcrumb } from '@/components/ui/breadcrumb' 2 3 <Breadcrumb> 4 <Breadcrumb.Item href="/">Home</Breadcrumb.Item> 5 <Breadcrumb.Item href="/docs">Docs</Breadcrumb.Item> 6 <Breadcrumb.Page>Button</Breadcrumb.Page> 7 </Breadcrumb>
Custom slash separator
Passing a separator prop to the root swaps the chevron for any JSX node — a slash character, a dot, a vertical bar, or an icon from a different set. The auto-injector uses whatever you pass once, so every position in the trail stays visually consistent without repeating the separator at each item.
Slashes suit file-path-style breadcrumbs where the trail represents a literal hierarchy: user settings, file tree navigation, storage keys. Dots work well for compact mobile layouts. For a branded look, pass a styled <span> that references design tokens so the separator picks up your theme's muted color automatically. The separator prop is typed as React.ReactNode, so there is no escape hatch needed for custom markup — any valid JSX works and inherits your Tailwind classes.
1 <Breadcrumb separator={<span>/</span>}> 2 <Breadcrumb.Item href="/">Home</Breadcrumb.Item> 3 <Breadcrumb.Item href="/settings">Settings</Breadcrumb.Item> 4 <Breadcrumb.Page>Profile</Breadcrumb.Page> 5 </Breadcrumb>
Next.js Link integration
Breadcrumb.Item renders as a plain <a> tag by default, which triggers a full page reload when clicked. In a Next.js app you want client-side routing on nav links, which means rendering each item as a <Link> instead of a raw anchor. Because the Breadcrumb lives in your codebase after install, the clean fix is to edit src/components/ui/breadcrumb.tsx once: swap the <a> inside the Item function for a <Link> from next/link, passing href and spreading the remaining props.
This is the "copy and own" pattern Drivn is built around — the component is yours the moment you run drivn add breadcrumb via the CLI. No asChild prop, no Slot wrapper, no runtime indirection. Update the file once and every breadcrumb across your app gets client-side routing without touching a single call site.
1 // src/components/ui/breadcrumb.tsx — after install 2 import Link from 'next/link' 3 4 function Item({ 5 href, 6 className, 7 children, 8 ...props 9 }: React.AnchorHTMLAttributes<HTMLAnchorElement> & { 10 href: string 11 children: React.ReactNode 12 }) { 13 return ( 14 <li> 15 <Link 16 href={href} 17 className={cn(styles.link, className)} 18 {...props} 19 > 20 {children} 21 </Link> 22 </li> 23 ) 24 }
Collapsed path with Ellipsis
Eight folders down, or a product buried in nested categories, and the trail either wraps onto a second line or pushes past the edge of its card. Breadcrumb.Ellipsis collapses the middle instead: keep the root, keep the current page, and replace everything between them with one glyph that signals there are levels here.
The component renders an <li> holding a size-9 span — a 36-pixel square, matching the tap target of an icon button — with a MoreHorizontal icon at size-4 and an sr-only "More pages" label, so assistive tech announces the gap instead of skipping past it. Drop it anywhere in the children list and the root's auto-injection places chevrons on both sides, exactly as it does for any other item.
It is non-interactive out of the box, which is the right default — a decorative collapse should not advertise a click that does nothing. When you do want the hidden levels reachable, wrap the ellipsis in a Popover or a dropdown at the call site and list the skipped segments inside. The Breadcrumb file itself needs no change.
1 <Breadcrumb> 2 <Breadcrumb.Item href="/">Home</Breadcrumb.Item> 3 <Breadcrumb.Ellipsis /> 4 <Breadcrumb.Item href="/docs/components"> 5 Components 6 </Breadcrumb.Item> 7 <Breadcrumb.Page>Button</Breadcrumb.Page> 8 </Breadcrumb>
Render dynamically from route segments
Static breadcrumbs work for fixed-depth pages, but most apps compute the trail from the current URL. The pattern is a small helper that splits pathname into segments, accumulates an href for each prefix, maps the segment to a human-readable label, and renders the array as a list of Breadcrumb.Item elements with the final entry as a Breadcrumb.Page.
For a Next.js App Router app, call usePathname() inside a client component, split the path on /, and filter out empty strings. Pair it with a small label map — { docs: "Docs", components: "Components" } — so URL slugs render as proper titles in the trail. This pattern scales to any depth without manual edits: new routes show up with correctly-formatted breadcrumbs automatically, and the final segment is always the current page. Drop the component into your app shell once and every page inherits the trail.
1 'use client' 2 import { usePathname } from 'next/navigation' 3 import { Breadcrumb } from '@/components/ui/breadcrumb' 4 5 const labels: Record<string, string> = { 6 docs: 'Docs', 7 components: 'Components', 8 examples: 'Examples', 9 } 10 11 export function DynamicBreadcrumb() { 12 const pathname = usePathname() 13 const segments = pathname.split('/').filter(Boolean) 14 15 return ( 16 <Breadcrumb> 17 <Breadcrumb.Item href="/">Home</Breadcrumb.Item> 18 {segments.map((segment, i) => { 19 const href = '/' + segments.slice(0, i + 1).join('/') 20 const label = labels[segment] ?? segment 21 const isLast = i === segments.length - 1 22 23 return isLast ? ( 24 <Breadcrumb.Page key={href}>{label}</Breadcrumb.Page> 25 ) : ( 26 <Breadcrumb.Item key={href} href={href}> 27 {label} 28 </Breadcrumb.Item> 29 ) 30 })} 31 </Breadcrumb> 32 ) 33 }
Install Drivn in one command
Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.
npx drivn@latest createRequires Node 18+. Works with npm, pnpm, and yarn.
Frequently asked questions
They are auto-injected at render time. The root calls React.Children.toArray(children).flatMap() and, for every child past the first, prepends a Breadcrumb.Separator element before it. The separator uses whatever JSX you pass via the root's separator prop, defaulting to a Lucide ChevronRight icon. You write only the items and the current page inside <Breadcrumb>, and the trail renders with visually consistent dividers without any per-position separator tags in your JSX.
Pass a separator prop to the root component once. The prop is typed as React.ReactNode, so any JSX works: a slash character (<span>/</span>), a custom icon (<ArrowRight className="w-3 h-3" />), or a branded element styled with your design tokens. The root hands that node to every auto-injected separator in the list, so a single override applies across every item position. To change the default globally, set the prop in a layout-level wrapper so every Breadcrumb inherits the same glyph.
Edit the local breadcrumb.tsx after install. Open src/components/ui/breadcrumb.tsx, import Link from next/link, and replace the <a> tag inside the Item function with a <Link>. The href prop and the {...props} spread transfer cleanly because LinkProps extends the same anchor attribute type. Every breadcrumb in your app then uses client-side routing with no call-site changes. This is the canonical "copy and own" pattern — Drivn never ships wrapper props for framework integration.
Use it when the trail depth exceeds the available horizontal space and wrapping onto two lines hurts more than collapsing the middle. Typical thresholds are four or more levels in a card-constrained layout, or any breadcrumb rendering inside a narrow sidebar or mobile viewport. Place the ellipsis between the root item and the deepest visible item, so users still see where they are and the top-level context. If you want the hidden levels to be clickable, wrap the ellipsis in a disclosure component like a Popover.
Call usePathname() from next/navigation inside a client component, split the pathname on /, filter empty strings, and map each segment to a Breadcrumb.Item with an accumulated href. Render the last segment as a Breadcrumb.Page so it picks up the current-page styling and the aria-current="page" marker. Keep a labels record that maps URL slugs to human-readable titles so the trail reads as "Docs / Components" instead of "docs / components". The pattern scales to any route depth without manual edits.

