Breadcrumb
The path trail for deep ERP hierarchies — cost center → PO → line
item. A landmark <nav> wrapping an ordered list,
not styled links, so screen-reader users can jump straight to it.
Not for progress through a flow — a breadcrumb says where
this record sits in a hierarchy you can climb, not how far through a task
you are. That is Stepper.
Path trail
The current page is plain text, not a link — you don't link to where you already are. Keep trails short: if yours runs past four levels, the hierarchy is the problem, not the component.
Markup
<nav aria-label="Breadcrumb">
<ol class="bo-breadcrumb">
<li><a href="/cost-centers">Cost centers</a></li>
<li><a href="/cost-centers/cc-4021">CC-4021</a></li>
<li aria-current="page">PO-88213</li>
</ol>
</nav>
<!-- The current page is plain text, not a link — you don't link to where
you already are. aria-current is the programmatic channel; the ol's
list semantics + aria-label="Breadcrumb" are what make it a landmark
a screen reader can jump to directly. --> Quick reference generated
| Class | Role |
|---|---|
| .bo-breadcrumb | block (root) |
State attributes: aria-current
API generated from CSS
| Blocks | bo-breadcrumb |
|---|---|
| ARIA styled | aria-current |
| JS required | None — CSS-only. |
- Wrap it in
<nav aria-label="Breadcrumb">— that is what makes it a landmark; the class only paints the separators. - Mark the current page with
aria-current="page"and render it as text, not a link. - Separators are CSS, not characters in your markup — so they never end up in a screen reader's output or a copy-paste.
Contrast — 17 AA pairs this component uses (generated, CI-gated)
| Text | on | Light | Dark |
|---|---|---|---|
| text-primary | bg-surface | 17.74 | 16.15 |
| text-primary | bg-canvas | 16.98 | 18.08 |
| text-secondary | bg-surface | 10.31 | 11.46 |
| text-secondary | bg-muted | 9.37 | 9.75 |
| text-muted | bg-surface | 7.56 | 6.65 |
| text-muted | bg-muted | 6.87 | 5.66 |
| bg-surface | text-primary | 17.74 | 16.15 |
| accent | bg-surface | 5.47 | 9.07 |
| text-primary | bg-hover | 16.12 | 13.75 |
| text-primary | bg-selected | 17.01 | 11.86 |
| text-secondary | bg-selected | 9.88 | 8.41 |
| text-primary | bg-surface-raised | 17.74 | 14.51 |
| text-secondary | bg-canvas | 9.86 | 12.82 |
| accent | bg-selected | 5.25 | 6.66 |
| accent | accent-subtle | 5.25 | 6.66 |
| accent | bg-muted | 4.97 | 7.72 |
| text-primary | bg-muted | 16.12 | 13.75 |
Maturity generated
- Introduced
- v0.3.0
- CSS floor
- Chrome/Edge 99 · Firefox 128 · Safari 17.4
- Alignment scored
- 2026-08-21
- Assistive-tech evidence
- None recorded
Pin this component's first release with npm i @busy-office/ui@0.3.0.
The floor is derived from this component's stylesheet alone — set by
@layer — so it sits at or below the
whole framework's Chrome/Edge 119 · Firefox 129 · Safari 17.5.
No assistive-technology runtime result is recorded for any component: it needs a human listening to VoiceOver and NVDA on owner hardware; no gate in this repo can simulate announcement behaviour.
What automation covers instead is test:axe across every page at 1440 and 390, and check:forced-colors — see
accessibility.
Design-system alignment generated
100% (18/18) — how closely this component follows the design language. Each rule is scored 0-3 against a checkable citation; rules that don't apply leave the denominator. Scored 2026-08-21.
| Rule | Score | Evidence |
|---|---|---|
| Typography | 3 / 3 | --bo-font-size-sm only, no raw font-size |
| Colour | 3 / 3 | zero raw colour; current page carries weight + primary ink, not colour alone |
| Spacing | 3 / 3 | zero raw dimension literals — every gap from a space token |
| Interaction | 3 / 3 | plain links ARE an interaction surface: the platform supplies the anchor's focus ring, Enter activation and navigation, and the component paints `.bo-breadcrumb a:hover` and renders the current crumb as non-link text under [aria-current="page"]. No behaviour ships for it, which the API table's JS row states as "None — CSS-only." and check-js-serves holds against behaviors.json's empty byComponent entry. Blind re-scored na->3 on 2026-09-04: the rubric admits na only where there is no interaction surface AT ALL, and a component shipping no behaviour earns 3 by saying so. |
| Content | 3 / 3 | opener carries the wrong-choice clause: "Not for progress through a flow" — a crumb says where a record sits in a hierarchy you can climb, not how far through a task you are, and the clause names and links Stepper for the other case |
| Fit | 3 / 3 | deep ERP hierarchies (cost center -> PO -> line item); the ERP suite emits every trail from ONE shared crumbs() helper in _shell.mjs, never hand-written markup, and create-ui's starter screen ships one |