Breadcrumbs
Hierarchical links show where a page belongs and give direct access to its ancestors.
On this page
Code
import { Breadcrumbs } from "@bosunkit/components/breadcrumbs";
import { House } from "lucide-react";
import type { ReactElement } from "react";
export const description: string =
"Parent destinations are real links; the current page is plain text with aria-current. Icons supplement the names.";
export default function Showcase(): ReactElement {
return (
<Breadcrumbs
label="Documentation hierarchy"
expandLabel="Show ancestors"
collapseLabel="Hide ancestors"
items={[
{ id: "home", label: "Design", href: "/", icon: <House /> },
{ id: "components", label: "Components", href: "/docs/components" },
{ id: "navigation", label: "Navigation", href: "/docs/components/navigation" },
{ id: "current", label: "Breadcrumbs" },
]}
/>
);
}
Breadcrumbs describe the current page's place in a hierarchy. The final item is text marked aria-current="page";
each ancestor with an href is a real link. Names match the destination titles. The component reads no router state.
Examples
Deep paths and controlled disclosure
maxItems counts destinations, including the root and current page; its default is four and its minimum is two.
The disclosure is an additional control. It reveals the middle ancestors in place and keeps keyboard focus on
the same button. The caller supplies both its expanded and collapsed names.
Code
import { Breadcrumbs } from "@bosunkit/components/breadcrumbs";
import { Switch } from "@bosunkit/components/switch";
import { useState, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"A deep hierarchy keeps the root, parent and current item visible. Reveal the middle ancestors, or use the switch to control disclosure externally.";
export default function LongPath(): ReactElement {
const [expanded, setExpanded]: [boolean, Dispatch<SetStateAction<boolean>>] = useState(false);
return (
<div style={{ display: "grid", gap: "var(--space-lg)" }}>
<label style={{ display: "flex", alignItems: "center", gap: "var(--space-sm)" }}>
<Switch checked={expanded} onCheckedChange={setExpanded} />
Show the complete path
</label>
<Breadcrumbs
label="Report example hierarchy"
maxItems={3}
expanded={expanded}
onExpandedChange={setExpanded}
expandLabel="Show all report ancestors"
collapseLabel="Collapse report ancestors"
items={[
{ id: "home", label: "Design", href: "/" },
{ id: "consumers", label: "Consumers", href: "/docs/consumers" },
{ id: "reports", label: "Reports and docs", href: "/docs/consumers/reports-and-docs" },
{ id: "types", label: "Report types", href: "/docs/consumers/report-types" },
{ id: "current", label: "An engineering review with a deliberately long title" },
]}
/>
</div>
);
}
Placement and navigation
Place breadcrumbs above the page heading. They complement the main navigation and provide a quick route upward. Do not use them for a task's progress; Steps names a workflow's stages and their states.
Pass unique item ids and one ordered path. The final item is current even if it has an href; a parent without an
href is plain text. An empty array renders an empty landmark, so omit the component when there is no hierarchy
to convey. One item can name a root page without creating an unnecessary link to itself.
Long names and small screens
Names wrap without clipping. Use a small maxItems when the available column is narrow and keep the destination's
complete name available. Icons are decorative beside text, and separators are hidden from assistive technology.
The disclosure remains a touch target and uses the shared focus ring. Expanded paths can take several lines.
expanded, defaultExpanded and onExpandedChange support controlled and local disclosure state. Changing the
page hierarchy does not change browser history; the application's route owns the actual path.
Accessibility and integration
Give each navigation landmark a useful label, such as “Report hierarchy”. Ordinary links use Tab and Enter;
the disclosure also supports Space. Internal paths use the provider's link adapter. Its native anchor props,
accessible names, refs and event handlers must reach the rendered link.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| labelrequired | string | – | Name of this navigation landmark, translated by the caller. |
| itemsrequired | readonly BreadcrumbItem[] | – | Ancestors in order, ending with the current page. Ids must be unique. |
| expandLabelrequired | string | – | Name of the control that reveals the hidden ancestors. |
| collapseLabelrequired | string | – | Name of the same control while all ancestors are visible. |
| maxItems | number | undefined | 4 | Maximum visible destinations while collapsed, including root and current page; at least two, four by default. |
| expanded | boolean | undefined | – | Whether all ancestors are visible. Omit to let the component own the disclosure. |
| defaultExpanded | boolean | undefined | false | Initial disclosure state in uncontrolled use. |
| onExpandedChange | ((expanded: boolean) => void) | undefined | – | Requests a disclosure change; navigation itself remains a real link. |
| className | string | undefined | – | Additional root classes. |
| testId | string | undefined | – | Root test id; the disclosure uses --expand. |
| ref | Ref<HTMLElement> | undefined | – | The navigation landmark. |
Reports / Engineering / Storage review
Weather / Crew / Storage review
Related
- Navigation: choose the right navigation pattern.
- Navigation list: persistent application destinations.
- Steps: progress through a task.
- Page header: title and actions below the hierarchy.
Usage reference: Atlassian breadcrumbs.