Breadcrumb
The path to the current resource as a hierarchy of links — separators, the current page, a collapsed ellipsis, and any routing library's link through render.
- Status
- Since
0.1.0- Accessibility pattern
- APG breadcrumb
Last updated
Install
Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Breadcrumb before installation. Retain the digest printed by this command.
pnpm exec vegastack-design verify breadcrumbInstall with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.
pnpm dlx shadcn@4.21.0 add @vegastack/breadcrumbRun the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.
Usage
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink render={<a href="/" />}>Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink render={<a href="/components" />}>
Components
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>;Anatomy
Examples
Composition
Breadcrumb is a nav labelled breadcrumb; BreadcrumbList is the ol inside it. Every segment
is a BreadcrumbItem, separators sit between items as their own li, and the last segment is a
BreadcrumbPage rather than a link.
Breadcrumb
└── BreadcrumbList
├── BreadcrumbItem
│ └── BreadcrumbLink
├── BreadcrumbSeparator
├── BreadcrumbItem
│ └── BreadcrumbLink
├── BreadcrumbSeparator
└── BreadcrumbItem
└── BreadcrumbPageBasic
A home link, a section link and the current page. BreadcrumbLink renders an a by default, so
href goes straight on it.
Custom separator
Pass children to BreadcrumbSeparator to replace the default chevron. The separator is
role="presentation" and aria-hidden, so whatever it renders is decoration and never enters the
accessible name of the trail.
Dropdown
Compose BreadcrumbItem with a DropdownMenu when a segment has siblings the reader can switch to.
The trigger is a real button, so it is reachable by keyboard and announces its expanded state.
Collapsed
BreadcrumbEllipsis stands in for the segments a long trail hides. It is role="presentation" and
aria-hidden — decoration, not a control — so when the hidden segments must stay reachable, wrap it
in a real trigger, as the example at the top of this page does with a Button size="icon-sm" and a
DropdownMenu.
Link component
render on BreadcrumbLink replaces the element it renders, which is how a routing library's link
gets the breadcrumb's styling and its data-slot. In a Next.js app that is
render={<Link href="/docs" />}; this page has no router, so the render target below is a plain
anchor.
RTL
Wrap the subtree in DirectionProvider direction="rtl" so Base UI resolves logical sides, and set
dir on the elements that portal out of it. The default separator carries rtl:rotate-180, so the
chevron points the way the text reads; a dropdown inside the trail aligns to end instead of
start.
API Reference
Breadcrumb
Breadcrumb adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
BreadcrumbList
BreadcrumbList adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
BreadcrumbItem
BreadcrumbItem adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
BreadcrumbLink
BreadcrumbLink adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
BreadcrumbPage
BreadcrumbPage adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
BreadcrumbSeparator
BreadcrumbSeparator adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
BreadcrumbEllipsis
BreadcrumbEllipsis adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
Accessibility
Breadcrumbis anavwitharia-label="breadcrumb"wrapping an ordered list, which is the APG breadcrumb pattern: assistive technology reads the trail as a landmark and the segments in order.BreadcrumbPageis the current page. It carriesaria-current="page"andaria-disabled, so it is announced as the destination the reader is already on rather than as a link they can follow.BreadcrumbSeparatorandBreadcrumbEllipsisare bothrole="presentation"andaria-hidden— neither is a control and neither adds words to the trail. A collapsed trail that must stay navigable puts the ellipsis inside a real trigger with its own accessible name.- Focus is the global 2px
:focus-visibleoutline frombase.css; nothing in the trail paints a ring glow.
| Contract | States tested |
|---|---|
| Behaviour | default, current, collapsed |
| Accessibility | native-or-base-ui-semantics, browser-accessibility-test, current, presentation-only-decoration |
| Visual | default, hover, focus-visible |
Do / Don't
Deviations
Upstream's file plus packages/ui/upstream/patches/breadcrumb.patch. Every hunk:
- A11Y-2 —
BreadcrumbLinkgainsrelative after:absolute after:inset-x-0 after:-inset-y-1 after:content-['']. Its visible box is one line of 14px text, measured 20px tall by the geometry lane — 4px under the floor — and a breadcrumb is a row of navigation controls, not prose, so SC 2.5.8's inline-text exception does not reach it. The invisible area grows the target on the block axis only, so two adjacent crumbs cannot fight for a pixel; nothing moves and nothing paints. The ellipsis is untouched: it isrole="presentation" aria-hidden, and upstream's own Collapsed example wraps it in aButton size="icon-sm"that is already 32px.breadcrumb.test.tsxasserts that shape, so a future upstream that makes the ellipsis itself the control fails here. - API-16 —
"use client"is added. Upstream ships none, butBreadcrumbLinkcallsuseRender, which callsReact.useRefinternally; under thereact-servercondition that hook isundefined, so a Server Component rendering a breadcrumb link throws on import. The boundary belongs at the lowest interactive leaf, and this file is it. - DOC-2 —
import { cn } from "cn"becomes@vegastack/design; our npm layer ownscn. - DOC-1 — prettier reflow plus the
registry-stamp.mjsprovenance header the three-copy model needs; no decision of its own.
Multi-Step Form
A guarded, branching flow around a Stepper — conditional steps, async guards, locking, deep links and resume, with no opinion about your fields.
Breadcrumb Cascade
Two additions to a breadcrumb trail for a file browser — a crumb that takes dragged rows, and a menu of a segment's siblings.