Breadcrumb
SourceA navigation trail showing where the current page sits in a hierarchy. Breadcrumb.Root is a <nav> landmark wrapping an ordered list of crumbs: Breadcrumb.Link for each ancestor, Breadcrumb.Separator between them, and Breadcrumb.Page for the current location. Each crumb can carry a leading Breadcrumb.Icon.
Basic
A trail is a Breadcrumb.Root around a single Breadcrumb.List, with one Breadcrumb.Item per crumb. Ancestors are Breadcrumb.Links; the last crumb is the Breadcrumb.Page, marked aria-current="page". Drop a Breadcrumb.Separator between items for the chevron.
"use client";
import { Breadcrumb } from "@stridge/noctis/breadcrumb";
export default function BreadcrumbBasic() {
return (
<Breadcrumb.Root>
<Breadcrumb.List>
<Breadcrumb.Item>
<Breadcrumb.Link href="#">Home</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Link href="#">Components</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>
);
}
With icons
Compose a leading Breadcrumb.Icon inside any Breadcrumb.Link or Breadcrumb.Page for a glyph. It clamps the icon to the trail's size and inherits the crumb's colour, so it tracks the label and lifts to the foreground on hover alongside it. Wrap an <Icon> (or any inline svg) inside it — don't put data-slot on the icon itself.
"use client";
import { Icon } from "@stridge/noctis";
import { Breadcrumb } from "@stridge/noctis/breadcrumb";
import { Folder, House } from "lucide-react";
export default function BreadcrumbIcon() {
return (
<Breadcrumb.Root>
<Breadcrumb.List>
<Breadcrumb.Item>
<Breadcrumb.Link href="#">
<Breadcrumb.Icon>
<Icon icon={House} />
</Breadcrumb.Icon>
Home
</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Link href="#">
<Breadcrumb.Icon>
<Icon icon={Folder} />
</Breadcrumb.Icon>
Projects
</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Page>Acme</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>
);
}
Sizes
size is md (the default) or the denser sm — the chrome trail that sits above a page title or in a header. It scales the type, the icon and separator glyphs, and the gaps together.
"use client";
import { Breadcrumb } from "@stridge/noctis/breadcrumb";
function Trail({ size }: { size: Breadcrumb.Size }) {
return (
<Breadcrumb.Root size={size} aria-label={`${size} breadcrumb`}>
<Breadcrumb.List>
<Breadcrumb.Item>
<Breadcrumb.Link href="#">Home</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Link href="#">Settings</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Page>Profile</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>
);
}
export default function BreadcrumbSizes() {
return (
<div className="flex flex-col gap-4">
<Trail size="md" />
<Trail size="sm" />
</div>
);
}
Custom separator
Breadcrumb.Separator draws a directional chevron by default — it mirrors under RTL. Pass children to swap it for a slash, a dot, or any inline svg; the separator stays presentational and hidden from assistive tech either way.
"use client";
import { Breadcrumb } from "@stridge/noctis/breadcrumb";
export default function BreadcrumbSeparator() {
return (
<Breadcrumb.Root>
<Breadcrumb.List>
<Breadcrumb.Item>
<Breadcrumb.Link href="#">Home</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator>/</Breadcrumb.Separator>
<Breadcrumb.Item>
<Breadcrumb.Link href="#">Docs</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator>/</Breadcrumb.Separator>
<Breadcrumb.Item>
<Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>
);
}
Collapsed trail
For a long path, stand in for the hidden middle crumbs with a Breadcrumb.Ellipsis inside its own Breadcrumb.Item. It draws an ellipsis glyph with a localized "More" name for assistive tech; make it the trigger of a Menu to reveal the collapsed crumbs on demand.
"use client";
import { Breadcrumb } from "@stridge/noctis/breadcrumb";
export default function BreadcrumbEllipsis() {
return (
<Breadcrumb.Root>
<Breadcrumb.List>
<Breadcrumb.Item>
<Breadcrumb.Link href="#">Home</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Ellipsis />
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Link href="#">Components</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator />
<Breadcrumb.Item>
<Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>
);
}
Routing
Breadcrumb.Link renders an <a> by default and accepts Base UI's render prop, so it composes onto a framework's router link while keeping its slot and skin: <Breadcrumb.Link href="/docs" render={<NextLink href="/docs" />}>Docs</Breadcrumb.Link>. From a server component, spread Breadcrumb.Link.props() onto the link element instead — the slot is the only styling hook the precompiled CSS needs.
Accessibility
The trail is a <nav> landmark named "Breadcrumb" (localized; pass aria-label to override — give each trail a distinct name if a page has more than one landmark). The crumbs are an ordered list, so assistive tech announces their order and depth; the current page is a non-interactive Breadcrumb.Page marked aria-current="page". Separators are presentational (aria-hidden) — the list order already conveys the hierarchy — and Breadcrumb.Icons are decorative, so a crumb's label always carries its meaning. Links show a focus-visible ring and the whole trail mirrors under RTL by construction.
Anatomy
Compose the trail from its parts. Breadcrumb.Root is the <nav>; everything else nests inside its Breadcrumb.List.
Breadcrumb.Root— the<nav>landmark; ownssize.Breadcrumb.List— the ordered list (<ol>) of crumbs and separators.Breadcrumb.Item— a crumb's<li>; wraps a link or the page.Breadcrumb.Link— an interactive ancestor crumb; an<a>by default, composable onto a router link viarender.Breadcrumb.Page— the current page crumb, markedaria-current="page".Breadcrumb.Separator— the presentational glyph between crumbs; a directional chevron by default.Breadcrumb.Ellipsis— a collapsed-run indicator for hidden crumbs.Breadcrumb.Icon— an optional leading glyph in a crumb; inherits its colour, clamps to the icon size.
Every rendered part carries a data-slot (noctis-breadcrumb on the root, noctis-breadcrumb-link on a link, and so on) for host-side styling — pair it with the data-size the root stamps, off which the per-size metrics are keyed.
On surfaces
The same trail re-tuned across the elevation scopes — the root canvas, an elevated panel, a menu, and a sunken well. It stays legible on every layer.
Design tokens
Generated from the component's declaration — the same graph that mints the CSS, so a variable name or its resolution default can't drift. The minted tokens are the public override seam: set one on any ancestor and every breadcrumb in that region retunes — e.g. .chrome { --noctis-breadcrumb-list-gap: var(--noctis-space-3); } opens up the trail. Colours aren't minted — the link, page, and separator read the muted/foreground/subtle roles directly, so a retheme propagates for free. See Customization for the full override ladder and Tokens for the whole graph.
API reference
Generated from the component's types — every prop, type, default, and description comes straight from the source. Each part gets its own table. Expand a row for the full type and description.