Skip to main content

Breadcrumb

Info:Navigation
38

A hierarchy trail showing where a page sits, with linked ancestors and a marked current location.

trail path hierarchy navigation trail crumbs

Live demo

live · @xtyle/astro

Breadcrumb

A path through the app

The last crumb is marked aria-current="page" automatically.

In-app crumbs

Give a crumb a value instead of an href and it becomes a keyboard-accessible button that fires select with { value, index } , for a trail that drives app state rather than navigating. Click an ancestor below.

Selected: (click a crumb)

Shortened crumbs with hover detail

A crumb's title 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). Hover the crumbs below to read each full path segment.

Every tone

The link tone tracks the active register: any tone in the roster, drawn at its panel-readable --{tone}-vivid ink.

Accents

tone="accent"
tone="accent-2"
tone="accent-3"
tone="accent-4"
tone="neutral"

Statuses

tone="success"
tone="info"
tone="warn"
tone="danger"

Named hues

tone="red"
tone="orange"
tone="yellow"
tone="green"
tone="blue"
tone="purple"
tone="brown"
tone="pink"
tone="cyan"
tone="gray"
tone="white"
tone="black"

Sizes

Three steps, scaled against the type ramp.

Small
Medium (default)
Large

Custom separator

Any string works; swap the slash for a chevron.

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.

Place at the top of a page or panel, above the Heading, to anchor where the user is.
Pair with a Link or Button home action for the root crumb when you need richer affordances than a plain anchor.
For app chrome, sits naturally inside a Toolbar's start group.
For an in-app trail (a crumb selects a node rather than navigating), give items a value instead of an href and listen for select (detail: { value, index }); the valued crumb is a keyboard-accessible button, so interactive breadcrumbs never need the slot.
Slotted crumbs (the items-less default slot) are styled by the component in light-DOM mode, but in shadow mode ::slotted() reaches only the top-level <li> (its layout), not the <a>/<span> inside; carry the trail in items when you want the component's link and current styling to reach every crumb.

Props

5 props, straight from the manifest.

PropTypeDefaultBindingsDescription
items BreadcrumbItem[]
html svelte astro
The trail, ordered root → current. Each item is `{ 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.
separator string /
html svelte astro
The glyph drawn between crumbs; decorative and hidden from assistive technology.
tone FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
accent
html svelte astro
Color tinting the ancestor links, from any tone in the roster: a semantic role, an accent variant, or a named hue.
size Size
sm md lg
md
html svelte astro
Type scale of the trail.
label string Breadcrumb
html svelte astro
The accessible name of the `<nav>` landmark.

Appearance

Variants

accent

.xtyle-breadcrumb--accent

Ancestor links tinted with the accent tone (the default).

neutral

.xtyle-breadcrumb--neutral

Ancestor links in neutral ink for a quieter trail.

Sizes

sm

.xtyle-breadcrumb--sm

Compact.

md

default
.xtyle-breadcrumb

Default.

lg

.xtyle-breadcrumb--lg

Large.

States

hover

.xtyle-breadcrumb__link:hover

Pointer over an ancestor link; it underlines.

focus-visible

.xtyle-breadcrumb__link: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, with their selectors.

breadcrumb

.xtyle-breadcrumb

The <nav> landmark wrapping the trail, carrying the tone and size classes.

--font-sans --text-sm --leading-normal --fg-2

list

.xtyle-breadcrumb__list

The ordered list laying the crumbs and separators out in a wrapping row.

--space-1

item

.xtyle-breadcrumb__link, .xtyle-breadcrumb__current

An ancestor link (anchor) or the current crumb (text). Links tint with the tone; the current crumb is bold neutral ink.

--accent-vivid --fg-0 --weight-medium --radius-sm --space-0 --space-1

separator

.xtyle-breadcrumb__separator

The decorative glyph between crumbs, hidden from assistive tech.

--fg-3

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 38/38 consumed tokens produced default register: 299 tokens

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-vivid

Slots

default
html svelte astro

Custom crumb markup (<li> items and separators) used when items is omitted.

Accessibility

Renders a <nav> landmark with an accessible name (aria-label, default "Breadcrumb") so screen readers can jump to and announce the trail.
The trail is an ordered list (<ol>), conveying sequence and position to assistive technology.
The current page is plain text marked aria-current="page", not a link. It is the destination, not a navigation target.
Separators are decorative and aria-hidden, so they are never read aloud between crumbs.
Link focus is shown with a token ring plus a transparent outline that the forced-colors base rule promotes to a real system outline.
An interactive crumb (an item with a value) is a real <button>, so it is a keyboard tab stop and activates on Enter and Space, not a <span> with a mouse-only handler.
An item's title is a hover tooltip and the crumb's accessible description, so a shortened or glyph label keeps its full value reachable without changing the crumb's accessible name.

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} />