Navigation
Breadcrumb
Where you are, as a path.
Usage
import { Breadcrumb } from '@misoto22/design'Notes
Where you are, as a path.
The last crumb is plain text with aria-current="page" rather than a link to itself — a self-link is the most common breadcrumb bug, and it makes a screen reader offer a navigation that goes nowhere.
Separators live in <li aria-hidden> so the trail is read as its items and not as "home slash work slash".
A middle crumb with no href is a defect that is invisible twice over: it renders as plain text in the same --ink-3-aa as the links beside it, and it carries no aria-current either — so it reads as the page the reader is on when it is not, and neither the browser nor a review says a word. The console does, in development.
Anatomy
| Element | Description |
|---|---|
| Trailrequired | A <nav> named by label, which defaults to “Breadcrumb”. It is a landmark whether or not the page wanted another one, set in mono-meta at --ink-3-aa. |
| Listrequired | An <ol> — the order is the hierarchy, not the reader’s history. It wraps rather than truncating, so a deep path takes a second line instead of losing a level. |
| Crumb link | An <a> for every item that has an href and is not the last. The label is a ReactNode, so whatever you put in it becomes part of the link’s accessible name. |
| Current crumbrequired | The last item, always: plain text at full --ink with aria-current="page", whether or not it was given an href. |
| Separator | A slash by default, in its own <li aria-hidden> between crumbs. Decorative by construction — it is never part of what is read out. |
Best practices
Do
- Pass label when a page can hold two trails: both nav landmarks are named “Breadcrumb” otherwise, and two landmarks with one name are two entries a reader cannot choose between.
- Give every crumb but the last an href — one without renders as plain text in the same colour as the links beside it, with no destination and no aria-current, so it reads as the page the reader is on when it is not. Development names the crumb rather than leaving an omission that is invisible in the browser and in review.
- Start the trail above the current page: a one-item Breadcrumb renders that item as the current crumb with no path at all, which is a landmark announcing a journey of length one.
Don’t
- Leave the href off the last item rather than passing one it ignores: the last crumb is text whatever you hand it, so an href there reads as a link in review and is not one at run time.
- Do not hide it on a phone to save a line. That is the layout where the sidebar is behind a drawer, which makes the trail the only way up a level that is on the screen.
Examples
default
Where you are, as a path. The last crumb is plain text carrying aria-current="page" and never a link to itself — a self-link is the most common breadcrumb bug, and it offers a screen reader a navigation that goes nowhere. The separators sit in their own aria-hidden list items, so the trail is read as its items rather than as home slash components slash. label names the nav landmark; a page that can hold two trails has to name both, or a reader gets two entries called Breadcrumb and no way to choose.
a deep path
A path deep enough to wrap, with a separator that is not the default slash. The list wraps rather than truncating, and that is the right trade: the level a truncating trail drops is usually the one the reader was heading for. The separator is decorative whatever is put in it — it lives in an aria-hidden list item and is never read out. Do not hide this on a phone to save a line. That is the layout where the sidebar is behind a drawer, which makes the trail the only way up a level that is on the screen at all.
page header
The trail above the title it ends on. Start it above the current page: a one-item Breadcrumb renders that item as the current crumb with no path at all, which is a landmark announcing a journey of length one. Every crumb but the last needs an href — one without renders as plain text in the same colour as the links beside it, with no destination and no aria-current, so it reads as the page the reader is on when it is not. The last crumb repeating the heading is not a duplication to fix: one is the path, the other is the page.
Invoice 2024-118
Issued 4 March, due 3 April. Unpaid.
Accessibility
- The last crumb is text with aria-current="page", never a link to itself.
- Separators are aria-hidden, so the trail is not read as “home slash work slash”.
- A middle crumb with no href takes no aria-current and no colour of its own, which is why the omission is reported in development instead of shipped as a crumb that impersonates the current page.