Breadcrumb
A navigation trail with separators, collapsible ellipsis, and a standalone back link for page headers.
Installation
$
Usage
import {
Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink,
BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, BreadcrumbBack,
} from "@/components/ui/breadcrumb"Examples
Default
Back Link
A standalone “up one level” affordance for page headers. Use size="lg" at header scale.
Collapsed
Collapse the middle of a long trail behind an ellipsis.
Collapsed with Dropdown
Wrap the ellipsis in a dropdown to reveal the hidden crumbs.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| renderBreadcrumbLink, BreadcrumbBack | React.ReactElement | - | Replaces the default <a> with your own element, e.g. render={<Link href="/" />}. Base UI merges props onto it. |
| sizeBreadcrumbBack | "default" | "lg" | "default" | default is inline/toolbar scale (14px); lg sits at page-header scale (20px). The chevron scales with it. |
| childrenBreadcrumbSeparator | React.ReactNode | - | Overrides the default chevron separator, e.g. pass a / for a slash-style trail. |
"use client"
import * as React from "react"
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"
import { useRender } from "@base-ui/react/use-render"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/registry/lib/utils"
/* ─────────────────────────────────────────────────────────
* BREADCRUMB
*
* A navigation trail. Not a Base UI primitive; pure semantic
* DOM (nav > ol > li). Links are polymorphic via Base UI's
* `render` prop (never `asChild`): pass `render={<Link />}` to
* swap in a router link.
* ───────────────────────────────────────────────────────── */
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
return (
<nav
data-slot="breadcrumb"
aria-label="breadcrumb"
className={className}
{...props}
/>
)
}
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
return (
<ol
data-slot="breadcrumb-list"
className={cn(
"flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground",
className
)}
{...props}
/>
)
}
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
return (
<li
data-slot="breadcrumb-item"
className={cn("inline-flex items-center gap-1.5", className)}
{...props}
/>
)
}
// Polymorphic link. Renders an <a> by default; pass `render={<Link />}`
// (or any element) to compose with a router. Never uses `asChild`.
function BreadcrumbLink({
className,
render,
...props
}: useRender.ComponentProps<"a">) {
return useRender({
render: render ?? <a />,
props: {
"data-slot": "breadcrumb-link",
className: cn(
"rounded-sm outline-none transition-colors duration-150 hover:text-foreground focus-visible:text-foreground focus-visible:ring-ring-focus focus-visible:ring-[3px]",
className
),
...props,
},
})
}
// The current page, the last crumb. Non-interactive on purpose.
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
return (
<span
data-slot="breadcrumb-page"
role="link"
aria-disabled="true"
aria-current="page"
className={cn("font-normal text-foreground", className)}
{...props}
/>
)
}
// Separator between crumbs. Defaults to a chevron; pass children (e.g. a
// slash) to override. Decorative, so hidden from assistive tech.
function BreadcrumbSeparator({
children,
className,
...props
}: React.ComponentProps<"li">) {
return (
<li
data-slot="breadcrumb-separator"
role="presentation"
aria-hidden="true"
className={cn("[&>svg]:size-3.5", className)}
{...props}
>
{children ?? <ChevronRight />}
</li>
)
}
// Collapsed marker for long trails. Decorative on its own; wrap it in a
// DropdownMenuTrigger to reveal the hidden crumbs.
function BreadcrumbEllipsis({
className,
...props
}: React.ComponentProps<"span">) {
return (
<span
data-slot="breadcrumb-ellipsis"
role="presentation"
aria-hidden="true"
className={cn(
"flex size-8 pointer-coarse:size-11 items-center justify-center [&>svg]:size-4",
className
)}
{...props}
>
<MoreHorizontal />
<span className="sr-only">More</span>
</span>
)
}
/* ─────────────────────────────────────────────────────────
* BACK LINK
*
* A standalone "up one level" affordance for page headers:
* a leading chevron-left + the parent's name. Sized `default`
* for inline/toolbar use, `lg` to sit at header scale. The
* chevron nudges left on hover to signal "go back".
* ───────────────────────────────────────────────────────── */
const backVariants = cva(
"group inline-flex w-fit items-center rounded-sm font-medium text-foreground outline-none transition-colors duration-150 focus-visible:ring-ring-focus focus-visible:ring-[3px] [&>svg]:shrink-0 [&>svg]:text-muted-foreground [&>svg]:transition-[color,transform] [&>svg]:duration-150 group-hover:[&>svg]:text-foreground motion-safe:group-hover:[&>svg]:-translate-x-0.5",
{
variants: {
size: {
default: "gap-1.5 text-sm [&>svg]:size-4",
lg: "gap-2 text-xl [&>svg]:size-5",
},
},
defaultVariants: {
size: "default",
},
}
)
function BreadcrumbBack({
className,
size,
children,
render,
...props
}: useRender.ComponentProps<"a"> & VariantProps<typeof backVariants>) {
return useRender({
render: render ?? <a />,
props: {
"data-slot": "breadcrumb-back",
className: cn(backVariants({ size }), className),
children: (
<>
<ChevronLeft />
{children}
</>
),
...props,
},
})
}
export {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
BreadcrumbBack,
}