Breadcrumb
A hierarchy trail showing where a page sits, with linked ancestors and a marked current location.
Live demo
Breadcrumb renders a location trail: an ordered list of ancestor links ending in the current page, with a separator glyph between each step. It is a <nav> landmark labeled "Breadcrumb" wrapping an <ol>; ancestors render as anchors and the final crumb renders as plain text carrying aria-current="page".
Pass the trail declaratively via the items array (each entry is { label, href?, value?, title?, current? }) and the engine builds the list, injects the separators, and marks the last item current. For an in-app trail where a crumb drives state instead of navigating (selecting an ancestor node, not following a URL), give the item a value and no href: it renders as a real button and fires a select event carrying { value, index } on click or Enter/Space, so interactive crumbs never have to drop to the slot. href wins when both are set. The separator glyph defaults to / and is purely decorative. A tone tints the ancestor links and three sizes scale the type. For fully custom crumbs, omit items and provide your own <li> markup in the default slot.
When to use
How this component composes with the rest of the set.
Props
5 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
{ label, href?, value?, title?, current? }. Items with an href (and not current) render as links; a non-current item with a value and no href renders as a button that fires select; the last item, or any item with current: true, renders as the current page. An optional title becomes the crumb's hover tooltip (and its accessible description), for an abbreviated or truncated label whose full value should still be reachable. In the HTML binding this is a JSON-string attribute. | ||||
<nav> landmark. |
Events
What the component emits, and what rides along on event.detail. The name in the
first column is the one addEventListener takes.
| Event | Detail | Bindings | Description |
|---|---|---|---|
Appearance
Variants
accent
Ancestor links tinted with the accent tone (the default).
neutral
Ancestor links in neutral ink for a quieter trail.
Sizes
sm
Compact.
md
Default.
lg
Large.
States
hover
Pointer over an ancestor link; it underlines.
focus-visible
Keyboard focus on a link: a token-colored ring, plus a transparent outline promoted to a real one in forced-colors mode.
Anatomy
The named parts that make up the component. A ::part() handle is reachable from your own stylesheet; the class beside it is the component's internal selector, which a shadow boundary keeps to itself.
breadcrumb
The <nav> landmark wrapping the trail, carrying the tone and size classes.
list
The ordered list laying the crumbs and separators out in a wrapping row.
item
An ancestor link (anchor) or the current crumb (text). Links tint with the tone; the current crumb is bold neutral ink.
separator
The decorative glyph between crumbs, hidden from assistive tech.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--accent-2-vivid--accent-3-vivid--accent-4-vivid--accent-vivid--black-vivid--blue-vivid--border-normal--border-thick--brown-vivid--cyan-vivid--danger-vivid--duration-fast--ease-standard--fg-0--fg-2--fg-3--font-sans--gray-vivid--green-vivid--info-vivid--leading-normal--neutral-vivid--orange-vivid--pink-vivid--purple-vivid--radius-sm--red-vivid--ring--space-0--space-1--success-vivid--text-body--text-sm--text-xs--warn-vivid--weight-medium--white-vivid--yellow-vividSlots
Custom crumb markup (<li> items and separators) used when items is omitted.
Accessibility
Code
A location trail
An ordered trail of linked ancestors ending in the current page; tone and separator are adjustable.
<xtyle-breadcrumb
items='[
{"label":"Home","href":"/"},
{"label":"Library","href":"/library"},
{"label":"Themes"}
]'
></xtyle-breadcrumb>
<xtyle-breadcrumb tone="neutral" separator="›" items='[
{"label":"Docs","href":"/docs"},
{"label":"Components","href":"/docs/components"},
{"label":"Breadcrumb"}
]'></xtyle-breadcrumb>
<xtyle-breadcrumb label="You are here">
<li class="xtyle-breadcrumb__item"><a class="xtyle-breadcrumb__link" href="/">Home</a></li>
<li class="xtyle-breadcrumb__separator" aria-hidden="true">/</li>
<li class="xtyle-breadcrumb__item"><span class="xtyle-breadcrumb__current" aria-current="page">Settings</span></li>
</xtyle-breadcrumb><script lang="ts">
import { Breadcrumb } from "@xtyle/svelte";
const trail = [
{ label: "Home", href: "/" },
{ label: "Library", href: "/library" },
{ label: "Themes" },
];
</script>
<Breadcrumb items={trail} />
<Breadcrumb tone="neutral" separator="›" items={trail} />---
import { Breadcrumb } from "@xtyle/astro";
const trail = [
{ label: "Home", href: "/" },
{ label: "Library", href: "/library" },
{ label: "Themes" },
];
---
<Breadcrumb items={trail} />
<Breadcrumb tone="neutral" separator="›" items={trail} />In-app crumbs (select, not navigate)
Give a crumb a value instead of an href and it becomes a keyboard-accessible button that fires select with { value, index }, so clicking an ancestor drives app state rather than following a URL.
<xtyle-breadcrumb id="tree-trail" label="Node ancestry" items='[
{"label":"root","value":"0"},
{"label":"window","value":"1"},
{"label":"toolbar"}
]'></xtyle-breadcrumb>
<script>
// a valued crumb drives app state instead of navigating
document.querySelector("#tree-trail").addEventListener("select", (e) => {
selectNode(e.detail.value); // { value, index }
});
</script><script lang="ts">
import { Breadcrumb } from "@xtyle/svelte";
const ancestry = [
{ label: "root", value: "0" },
{ label: "window", value: "1" },
{ label: "toolbar" }, // the current node: no value, not clickable
];
</script>
<Breadcrumb label="Node ancestry" items={ancestry} onselect={(e) => selectNode(e.detail.value)} />---
import { Breadcrumb } from "@xtyle/astro";
const ancestry = [
{ label: "root", value: "0" },
{ label: "window", value: "1" },
{ label: "toolbar" },
];
---
<Breadcrumb label="Node ancestry" items={ancestry} />
<script>
document.querySelector("xtyle-breadcrumb").addEventListener("select", (e) => {
selectNode(e.detail.value);
});
</script>Shortened crumbs with hover detail
A title on an item reveals the full value behind an abbreviated, truncated, or glyph label on hover, and carries it to assistive tech as the crumb's accessible description.
<!-- a title reveals the full value behind a shortened crumb -->
<xtyle-breadcrumb items='[
{"label":"~","href":"/","title":"/home/ada"},
{"label":"…","href":"/p","title":"projects/2026/q3"},
{"label":"report.md","title":"projects/2026/q3/report.md"}
]'></xtyle-breadcrumb><script lang="ts">
import { Breadcrumb } from "@xtyle/svelte";
const path = [
{ label: "~", href: "/", title: "/home/ada" },
{ label: "…", href: "/p", title: "projects/2026/q3" }, // middle-truncated, full path on hover
{ label: "report.md", title: "projects/2026/q3/report.md" },
];
</script>
<Breadcrumb items={path} />---
import { Breadcrumb } from "@xtyle/astro";
const path = [
{ label: "~", href: "/", title: "/home/ada" },
{ label: "…", href: "/p", title: "projects/2026/q3" },
{ label: "report.md", title: "projects/2026/q3/report.md" },
];
---
<Breadcrumb items={path} />