# Breadcrumb

> Navigation trail with current page indication; middle items collapse into an ellipsis menu when the trail overflows or exceeds `maxItems`.

- Status: stable
- Group: navigation
- Page: https://www.digitaltableteur.com/design-system/components/breadcrumb
- Contract: https://www.digitaltableteur.com/contracts/v1/Breadcrumb.contract.json

## When to use

Breadcrumb renders the page's location trail as a labelled nav landmark containing an ordered list. Pass `items` in root-to-current order; entries with `href` render as links except the last, which always renders as the current page in plain text. Middle entries without `href` render as text too, so levels without landing pages stay honest. When the trail is wider than its container (or longer than `maxItems`), the middle entries collapse into an ellipsis button that opens a menu of the hidden levels; the first entry and the current page stay visible. Keep labels short; a breadcrumb is orientation, not prose.

## When not to use

- Do not include the home icon as a separate item. Use `label: 'Home'` with `href: '/'` so the AT user hears a word, not a glyph.
- Do not skip levels to make the trail shorter. If the user is at `/work/acme`, the parent must be `/work`, not `/`.
- Do not render the breadcrumb above a hero; it gets lost. Place it immediately above the page title so it forms a single "where am I" block.

## Look-alikes

The contract names no look-alike with a deciding condition.

## Props

| Prop | Type | Default | Description | Required |
| --- | --- | --- | --- | --- |
| `items` | `BreadcrumbItem[]` | none | Breadcrumb items in root-to-current order (label, optional href); the last renders as plain text. | Yes |
| `aria-label` | `string` | none | Accessible name for the nav landmark. Defaults to the translated "Breadcrumb" (`breadcrumb.label`). | No |
| `underline` | `"always" \| "hover" \| "none"` | `always` | Underline mode forwarded to the Link for each trail item, the same contract as Link: "always" shows the underline permanently, "hover" reveals it on hover and keyboard focus, "none" omits it. Defaults to `always`. | No |
| `maxItems` | `number` | none | Static collapse cap. When set to a positive number smaller than the item count, the middle items collapse into an ellipsis menu WITHOUT measuring: the first `maxItems - 2` leading items and the current item stay visible. Leave unset (or 0) for automatic width-based collapse (the default). | No |
| `collapseLabel` | `string` | none | Accessible name for the ellipsis menu trigger. Defaults to the translated "Show N hidden breadcrumbs" (`breadcrumb.showHiddenOne` / `breadcrumb.showHiddenOther`). | No |
| `homeIcon` | `boolean` | `false` | Render the first item as a house icon instead of its text label. The item's label becomes the icon's accessible name, so screen readers still announce it (e.g. "Home"). Defaults to `false`. | No |

## Variants

- Allowed `underline` values: `always`, `hover`, `none` (default `always`).

## Invalid combinations

The contract records no invalid combinations.

## Keyboard

| Key | Behaviour |
| --- | --- |
| Tab | Moves focus to the control and on to the next focusable element. (standard) |
| Enter | Activates the focused control. (standard) |
| Space | Activates or toggles the focused control. (standard) |
| ArrowDown | Moves focus or the value in that direction. (standard) |
| ArrowUp | Moves focus or the value in that direction. (standard) |
| Escape | Closes or dismisses the open layer. (standard) |

Rows marked (standard) name a key the contract lists without a description; the behaviour shown is the usual one for that key.

## Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

| Level | Rule | How it is checked |
| --- | --- | --- |
| MUST | ARIA: Nav landmark. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Aria-label. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Current page on last item. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Default names follow the active language (nav "Breadcrumb" from `breadcrumb.label`; ellipsis "Show N hidden breadcrumb(s)" from `breadcrumb.showHiddenOne` / `breadcrumb.showHiddenOther`, singular or plural by count); aria-label and collapseLabel override them. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | Required stories produce no axe violations at the configured severity. | Automated by `npm run test:stories:matrix:ci`. WCAG 2.5.8. |
| MUST | The accessibility tree (role, name, state) matches the committed snapshot for every required story. | Automated by `npm run test:stories:matrix:ci`. WCAG 1.3.1, 4.1.2. |
| MUST | The component remains legible and operable under a real browser forced-colors: active pass. | Automated by `npm run test:stories:hc`. |
| MUST | Every documented keyboard interaction works as specified. | Not yet verified: no evidence record. WCAG 2.1.1, 2.1.2. |
| MUST | A human completed an end-to-end accessibility review of this component. | Manual review, last on 2026-11-04. |
| SHOULD | Order items root -> current; the last item is the page the user is standing on. | Not stated in the contract. |
| SHOULD | Rely on the translated default names, or pass aria-label (and collapseLabel) when a page has more than one trail and each needs its own name. | Not stated in the contract. |
| SHOULD | Point hrefs at real route segments so every linked level is actually navigable. | Not stated in the contract. |
| SHOULD | Omit href on middle levels that have no landing page; they render as plain text instead of dead links. | Not stated in the contract. |
| SHOULD NOT | Do not start every trail with the site name; begin at the section root ("Home" at most). | Not stated in the contract. |
| SHOULD NOT | Do not hand-author "…" items to fake a collapsed middle; the trail collapses its middle items into an ellipsis menu itself, on overflow or at `maxItems`. | Not stated in the contract. |

## Install and import

- Install: `npm install @digitaltableteur/react` (version 0.9.1, restricted access on npm).
- Import: `import { Breadcrumb } from "@digitaltableteur/react";`
- Entry point: `@digitaltableteur/react/navigation` exports it too.
- Styles: import `@digitaltableteur/react/style.css` once at the app boundary.
- Also available as the custom element `<dt-breadcrumb>`; see the custom elements manifest.

## Links

- Machine-readable contract (Design System Contract 1.0): https://www.digitaltableteur.com/contracts/v1/Breadcrumb.contract.json
- Markdown version of this page: https://www.digitaltableteur.com/design-system/components/breadcrumb.md
- Component index as JSON: https://www.digitaltableteur.com/design-system/components.json
- All components: https://www.digitaltableteur.com/design-system/components
- Source: The implementation lives in a private repository. This page, its Markdown twin and the contract are generated from it at build time and are the public source of truth.
