AppBreadcrumb
Hero example
When to use
Reach for AppBreadcrumb at the top of every dashboard page that sits inside the hierarchical navigation — entities/ent_… › Filings › Delaware AR 2026. The trail tells the user where they are and how to back out one level. The component handles three crumb shapes: plain (no href or onClick), interactive link (href set), interactive button (onClick set). The last crumb is always the current page and renders as a non-interactive <span> with aria-current="page".
Don't reach for AppBreadcrumb for non-hierarchical navigation — the trail implies "you got here by descending through these ancestors." For lateral tabs use SlidingPill; for cross-domain pivots use a route-grammar nav primitive. Don't use AppBreadcrumb on the marketing site either — the dashboard hierarchy doesn't exist there.
Anatomy
Three structural parts:
<nav aria-label="Breadcrumb">. The outer element carries the breadcrumb landmark role. Screen readers can jump to it via landmark navigation.<ol class="m-crumbs__list">. Each crumb is an<li>containing either a<span aria-current="page">(last crumb), an<a>(withhref), a<button>(withonClickonly), or a plain<span>(no interactivity). ACrumbSepSVG sits between consecutive crumbs.- Right slot. Optional. Renders at the trailing edge with
margin-left: auto— typical use is a context-menu trigger ("⋯") or a small action button ("Edit").
Mono crumbs (mono: true) render in Geist Mono at 11.5px — for resource IDs, file paths, and other code-like identifiers.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| crumbsrequired | Crumb[] | — | — |
| right | React.ReactNode | — | — |
States
| State | Trigger | Visual |
|---|---|---|
| Default crumb | Crumb with no interactivity | Muted text (--fg-muted) |
| Linked crumb | href set | Same color; hover brightens to --fg; focus ring on Tab |
| Button crumb | onClick set | Same as linked but renders as <button> |
| Current crumb | Last in crumbs[] | Foreground --fg, weight 500, aria-current="page" |
| Empty | crumbs: [] | Returns null — nothing renders |
Density
In compact, the gap between crumbs drops from 6 to 4px. Font sizes and separator dimensions stay constant.
Themes
Tokens consumed
Current crumb reads --fg; earlier crumbs read --fg-muted. Separator reads --hairline-strong.
Accessibility
- Keyboard interactions. Interactive crumbs (link or button) are reachable via Tab. Enter or Space activates. Non-interactive crumbs (plain or current) are skipped.
- ARIA roles and properties. Outer
<nav aria-label="Breadcrumb">. List is<ol>. Last crumb carriesaria-current="page". Separator SVG carriesaria-hidden. - Focus order. DOM order — earliest crumb first, current crumb last (not focusable).
- Screen-reader expectations. Announces as "Breadcrumb, list,
{N}items:{crumb 1}, link;{crumb 2}, link; …;{current crumb}, current page." - Reduced motion. No motion to suppress.
- Forced colors. Separators →
ButtonBorder; current →HighlightText; earlier →ButtonText. - WIG rules.
<nav>for the landmark (semantic-element rule).aria-current="page"on the last crumb (WIG navigation-state rule). Link vs button choice depends on whether the crumb navigates to a different page (<a>) or triggers an in-page action (<button>).:focus-visiblering on interactive crumbs.
Do / Don't
href for crumbs that navigate to a route. Right-click "open in new tab" works as expected (WIG link-vs-button rule).onClick to navigate. The middle-click / cmd-click affordance breaks.mono: true for crumbs that show resource IDs (ent_a1b2c3) or file paths. The mono treatment signals "code-like identity."Recipes
This component appears in:
- Docs corpus recipe — every document detail page.
- Board recipe — board-meeting detail pages.
- Equity recipe — grant detail pages.
Code example
import { AppBreadcrumb } from "@matter/components";
export function EntityDetailHeader({ entity, filing }: { entity: Entity; filing: Filing }) {
return (
<AppBreadcrumb
crumbs={[
{ label: "Entities", href: "/entities" },
{ label: entity.legal_name, href: `/entities/${entity.id}` },
{ label: entity.id, href: `/entities/${entity.id}`, mono: true },
{ label: "Filings", href: `/entities/${entity.id}/filings` },
{ label: filing.title },
]}
right={<ContextMenuTrigger />}
/>
);
}Source
packages/components/src/AppBreadcrumb/AppBreadcrumbEyebrow
11px, 0.18em tracked, uppercase soft-grey label that sits above a section headline. Always followed by a 24px gap. Pass `mono` for tabular numeric or code-flavored content.
EndpointBadge
Translucent pill labelling an HTTP endpoint — verb (method-colored) and path (mono). Omit the path for verb-only mode (the V1 VerbPill role).