C-49 · Components · Navigation
All elements · Breadcrumb on the Components page
Last checked 2026-10-22 · Awaiting approval · Accessibility tests
Approve Breadcrumb
Approving as
Guidance
When to use
- Show where a page sits in a hierarchy two or more levels deep, such as a case inside a program inside a department, or a document inside nested folders.
-
Put it at the top of the content area, above the page title, in the shell's content header
(
.qf-page-header). - Let users move up to any parent level in one step, especially when they arrived from search or a link and skipped the levels above.
-
Collapse the middle of a deep path (more than five levels) behind the
__morebutton, keeping the root and the last two levels in view.
When to consider something else
- When the hierarchy is the main way users move around the app, give it a Side navigation; breadcrumbs only add to it. See SideNavigation.
- When the user moves through steps of a process rather than levels of a hierarchy, use Step indicator. See StepIndicator.
- When the user browses and opens folders in place, use Tree. See Tree.
- When the app is flat (every page one level below home), leave breadcrumbs out; a Home link would be the only crumb.
Usability
- Use each level's page title as its crumb, so the crumb and the heading the user lands on match.
- Start at the app's root (Home, or the module's name) and end at the current page.
- Show the current page as plain text, not a link, marked
aria-current="page". -
Let a long path wrap by default; use
data-overflow="truncate"only in a fixed-height bar, and give each cut level atitlewith its full name. - Keep the trail the same on every visit to a page: it shows where the page lives, not the user's history.
- Don't use breadcrumbs as the only navigation.
- Don't use them to show the steps of a form or the user's browsing history.
- Don't hide the root or the current page when collapsing; hide only the middle.
- Don't put actions (Edit, Share) in the trail.
Accessibility
Keyboard
| Keys | Action |
|---|---|
| Tab / Shift+Tab | Moves through the links in order (and the … button when the path is collapsed); the current page is not focusable. |
| Enter | Follows the focused link. |
| Enter or Space on … | Reveals the hidden levels in place and moves focus to the first of them. |
Roles and names
-
The block is a
navlandmark named "Breadcrumb" witharia-label; it holds an ordered list (ol), so screen readers announce the number of levels. -
Each level is a
li.qf-breadcrumbs__item; every level but the last holds a link (.qf-breadcrumbs__link). -
The last level is the current page: a
spanwitharia-current="page", not a link. -
Separators are drawn by CSS (
::before), so they are not read and are not in the list's text. - The Home icon is
aria-hidden; the link keeps its visible text "Home". -
The collapse button is a
buttonnamed "Show N more levels", with noaria-expanded(it is not a toggle); once pressed it is removed and the levels it hid are in the list.
Focus
- Links and the … button show the shared focus ring.
- Revealing the collapsed levels moves focus to the first of them, so focus is never lost with the removed button.
Other requirements
- Links are underlined and in the link color (5.58:1 light, 9.23:1 dark), so they are not told apart by color alone (1.4.1); the current page is bold body ink.
-
Each link and the … button are at least 24px tall (
--qf-breadcrumb-target), meeting 2.5.8. - By default the trail wraps at 320px and 400% zoom instead of scrolling (1.4.10).
-
A truncated level keeps its full name in the DOM, so screen readers read all of it; the
titleshows it to pointer users.
Test your implementation too. This guidance covers the element as specified here. How a screen composes it (labels, order, announcements) still needs its own keyboard and screen reader check.
Accessibility tests
Passed the gate (run 358b316 on 2026-10-22): no finding in any theme. Awaiting a person’s approval of the checklist below.
| Area | Automated | A person checks |
|---|---|---|
| General | Passed | Color is never the only cue, text alternatives say the same thing as the graphic, and the element reads the same in the light and the dark theme. |
| Zoom | Passed | At 200% zoom, at 320 CSS pixels wide and with the WCAG text-spacing overrides, nothing is lost, clipped or overlapping. |
| Keyboard | Passed | Every row of the Keyboard table works, focus is always visible and never trapped, and the tab order follows the reading order. (3 rows) |
| Screen reader | Passed | With NVDA or JAWS on Windows and VoiceOver on macOS, names, roles and states are announced as Roles and names says, and changes are announced once. (6 items) |
Approving. When the checklist passes on the checked run, record it with
bun run a11y:approve -- breadcrumb --by "Your name" and commit
a11y/approvals.json with the rebuilt pages.
All test status
Package
Consumers link one stylesheet, css/classic/index.css, which includes every element. The
files below are where this element is defined.
Latest updates
| Date | Version | Breaking | Description |
|---|---|---|---|
| 2026-10-20 | 0.1 | No |
Breadcrumb (C-49): the shell's .qf-breadcrumbs is cataloged and its rules move from
composites/shell.css to components/breadcrumb.css; the content header
(.qf-page-header) keeps using it. nav[aria-label="Breadcrumb"] ›
ol.__list › li.__item, every level a __link but the
current page (aria-current="page"), CSS-drawn separators, 24px targets. Long paths
wrap by default; data-overflow="truncate" keeps one line and cuts the levels above
the current page first; a deep path hides its middle (__item[hidden]) behind a
__more button that reveals it in place
|