Breadcrumbs look trivial, which is exactly why they are so often broken for screen reader users. A trail rendered as a row of links separated by slash characters reads aloud as "Home slash Products slash Wireless slash Headphones" with no indication that it is a navigation aid, no signal of which page you are on, and decorative separators announced as literal punctuation. Accessible breadcrumbs fix all three problems with a small, well-understood markup pattern.
This guide is for developers who want the exact structure that conveys hierarchy to assistive tech: the nav landmark, a descriptive aria-label, aria-current="page" on the final item, and the correct way to hide separators. Every example is copy-paste ready and maps to specific WCAG 2.2 success criteria.
The baseline pattern for accessible breadcrumbs
The accepted structure wraps an ordered list inside a nav landmark. The list communicates sequence and count, the nav exposes the trail as a discoverable landmark, and the label distinguishes it from the other navigation regions on the page.
Here is the full pattern, with the current page marked and separators handled in CSS rather than in the markup:
<nav aria-label="Breadcrumb"> <ol> <li><a href="/">Home</a></li> <li><a href="/products">Products</a></li> <li><a href="/products/audio">Audio</a></li> <li><a href="/products/audio/headphones" aria-current="page">Headphones</a></li> </ol> </nav>
Use an ordered list, not an unordered one. The trail is a sequence from root to current page and the order carries meaning. Screen readers announce "list, 4 items" and let users navigate item by item, which immediately tells someone how deep the current page sits in the hierarchy. That count is information a row of inline links cannot convey.
- The nav element creates a navigation landmark users can jump to directly with rotor or landmark shortcuts.
- The ol/li structure exposes position ("3 of 4") and total depth.
- aria-current="page" identifies the page the user is on without relying on visual styling alone.
Why the nav landmark needs aria-label
A page commonly has several nav landmarks: primary navigation, a footer menu, and the breadcrumb. When a screen reader user pulls up the list of landmarks, three entries all reading "navigation" are useless. aria-label="Breadcrumb" gives this one a distinct accessible name, so the rotor shows "Breadcrumb, navigation" and the user can target it instantly.
Two rules keep the label clean. Do not include the word "navigation" in the label, because the role already announces it; aria-label="Breadcrumb navigation" produces the redundant "Breadcrumb navigation navigation." And if you have more than one breadcrumb-style trail on a page, give each a unique label so they remain distinguishable. This supports WCAG 2.4.1 Bypass Blocks (Level A) by making the region directly reachable through a labelled landmark.
If you prefer to reference visible text instead of a hard-coded string, aria-labelledby pointing at a visually hidden heading works too, but for a single static word, aria-label is simpler and easier to maintain.
aria-current="page": marking where the user is
The last crumb represents the current page. Marking it with aria-current="page" tells assistive tech "you are here," and most screen readers announce "current page" when reading that item. This is the single most overlooked attribute in breadcrumb markup.
There is a real decision about whether the final crumb should be a link at all. Two valid approaches:
- Keep it as a link to the current URL with aria-current="page". Self-referential but consistent, and predictable for keyboard users tabbing through.
- Render it as plain text (no anchor) with aria-current="page" on a span. This avoids a link that goes nowhere, which some users find confusing.
Use the literal value page, not true. aria-current accepts a token set (page, step, location, date, time, true), and page is the semantically correct one for a breadcrumb trail. aria-current="true" works but is less specific and produces a vaguer announcement. Do not rely on color or font weight alone to show the current crumb, since that fails users who cannot perceive the visual difference; the attribute is what carries the meaning to assistive tech.
Handling separators so they are not read aloud
Slashes, chevrons, and arrows between crumbs are decorative. If you put them in the HTML as text, screen readers will read them, turning the trail into "Home slash Products slash Audio." The fix is to render separators in CSS so they never enter the accessibility tree:
nav[aria-label="Breadcrumb"] li + li::before { content: "/"; padding: 0 0.5rem; color: #6b7280; }
Generated content from ::before is presentational and is ignored by assistive tech, so the separator is seen but not announced. If you must keep separators in the markup (for example, inline SVG chevrons), neutralize them: add aria-hidden="true" to each separator element, and for an SVG also give it focusable="false" to keep it out of the tab order in older browsers. Either way, the goal is the same: the crumb labels reach the screen reader and the decoration does not.
While you are styling, check the separator and link colors against the page background. Breadcrumb text is often small and muted, which is where contrast bugs hide. Normal-size text needs a 4.5:1 ratio against its background (large text, 18pt or 14pt bold and up, needs 3:1); run your values through the contrast checker before shipping.
Framework gotchas and dynamic trails
In component frameworks, breadcrumbs are usually generated from a route. Two issues recur. First, make sure aria-current is applied only to the last item, derived from the route, not hard-coded, or you will end up with multiple "current page" announcements after a navigation. Second, in single-page apps the breadcrumb updates without a full page load, so the landmark and the current item must reflect the new route on each transition. Pair that with a focus move or a status-message update so the change is perceivable; communicating a route change politely is what WCAG 4.1.3 Status Messages (Level AA) is about.
A truncated breadcrumb (collapsing the middle into an ellipsis on narrow screens) needs the collapse control to be a real button with an accessible name like "Show full breadcrumb trail," not a bare ellipsis character. Hidden crumbs should be removed from the accessibility tree or genuinely expandable, never just visually clipped while still being announced.
Because each crumb is a link, the WCAG 2.2 target size guidance applies: 2.5.8 Target Size (Minimum), Level AA, asks for a 24 by 24 CSS pixel target (with spacing exceptions). Tightly packed crumbs on mobile are an easy way to fail it, so give them enough padding or spacing to clear the threshold.
Where this fits in WCAG and EAA compliance
Breadcrumbs are not a standalone success criterion, but a correct implementation contributes to several. 2.4.1 Bypass Blocks (Level A) is supported by the labelled landmark. 1.3.1 Info and Relationships (Level A) is satisfied by the list structure conveying hierarchy programmatically. 4.1.2 Name, Role, Value (Level A) is met by aria-current communicating state, and on mobile the link targets engage 2.5.8 Target Size (Minimum, AA).
Under the European Accessibility Act (Directive (EU) 2019/882), which applies from 28 June 2025, the baseline for in-scope products and services is WCAG 2.2 Level A and AA via the harmonised standard EN 301 549. Navigation patterns like breadcrumbs are exactly the kind of detail conformance assessments check. For the legal framing see our overview of the European Accessibility Act and the harmonised standard at EN 301 549.
Most breadcrumb defects (missing landmark label, absent aria-current, audible separators) are catchable in minutes. Run your pages through the free AccessScan checker to flag landmark, naming, and contrast issues, then verify the trail by ear with a screen reader, since automation cannot confirm that the announced order actually matches the visual hierarchy.