Accessible Breadcrumb Navigation: The WAI-ARIA Pattern for E-Commerce Category Pages
Quietramp ·
Accessible Breadcrumb Navigation: The WAI-ARIA Pattern for E-Commerce Category Pages
Quick answer: A breadcrumb trail should be a real list of links (<ol> of <a> elements)
wrapped in a <nav> landmark labeled with aria-label="Breadcrumb" (or aria-labelledby), with
aria-current="page" on the link representing the current page. That’s the entire WAI-ARIA
Authoring Practices Guide (APG) Breadcrumb pattern
— no custom keyboard handling needed, since it’s built entirely from native links. A row of plain
text separated by > characters, or a <div> with click handlers standing in for links, gives a
screen reader no indication it’s a navigation trail at all.
This article covers technical accessibility practice, not legal advice — it explains what WCAG 2.1 AA requires for navigation components and how to implement it, not whether a specific site carries legal risk.
Where this shows up on an e-commerce site
Breadcrumbs are near-universal on category and product pages: “Home > Women > Shoes > Sneakers,” or a filtered path like “Home > Sale > Under $50.” They matter more in e-commerce than on a simple brochure site because catalog hierarchies are often three or four levels deep, and a shopper who lands on a product page from search or a shared link has no other on-page cue for how they got there or how to step back up one level. This is Quietramp’s own observation from reviewing e-commerce sites, not something the spec itself calls out — the APG defines the pattern, not where a store should use it.
The APG’s own definition is short and direct: “A breadcrumb trail consists of a list of links to the parent pages of the current page in hierarchical order. It helps users find their place within a website or web application.”
Why a plain-text or div-based breadcrumb fails
1. No structure or list semantics (fails SC 1.3.1 Info and Relationships)
WCAG SC 1.3.1 Info and Relationships
(Level A) requires that “information, structure, and relationships conveyed through presentation
can be programmatically determined or are available in text.” A sighted user reads “Home > Women >
Shoes > Sneakers” as an ordered hierarchy purely from the > characters and left-to-right layout.
Nothing about that is programmatically available unless the markup says so directly — a <span>
full of text and literal > glyphs is, to a screen reader, one run of text. It doesn’t announce as
a list, doesn’t convey that there are four items, and gives no signal about which one represents
the page the user is currently on.
2. Non-link elements standing in for links (fails SC 4.1.2 Name, Role, Value)
WCAG SC 4.1.2 Name, Role, Value
(Level A) exists so that “for all user interface components… the name and role can be
programmatically determined.” Some breadcrumb implementations style each level as a <span> or
<div> with an onclick handler instead of a real <a href> — often to avoid default link
underline/color styling rather than override it with CSS. A screen reader announces that element as
plain text with no indication it’s interactive, and it typically isn’t in the keyboard Tab order at
all, since only genuinely focusable elements (links, buttons, and anything given an explicit
tabindex) are.
3. Truncated category names with no full text available (fails SC 2.4.4 Link Purpose)
WCAG SC 2.4.4 Link Purpose (In Context) (Level A) requires that “the purpose of each link can be determined from the link text alone or from the link text together with its programmatically determined link context.” Long category names get visually truncated with an ellipsis to fit a narrow breadcrumb bar — “Women’s Athletic Footwear & Acce…” — and if the truncation is done by simply cutting the visible text rather than truncating only the display while keeping the full string as the link’s accessible name, a screen reader reads out the cut-off fragment as if it were the whole link.
The fix: the APG Breadcrumb pattern
Per the APG’s Roles, States, and Properties section, the pattern has three requirements:
- “Breadcrumb trail is contained within a navigation landmark region.”
- “The landmark region is labelled via
aria-labeloraria-labelledby.” — necessary because most pages already have a primary site-navigation<nav>(the main menu); without a label, assistive technology has no way to distinguish the two navigation regions from each other. - “The link to the current page has
aria-currentset topage. If the element representing the current page is not a link,aria-currentis optional.”
The APG’s own worked example page
shows exactly what that looks like in markup — notably, it keeps the current-page item as a link
(with an empty href) rather than removing the link entirely:
<nav aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
<li><a href="/women">Women</a></li>
<li><a href="/women/shoes">Shoes</a></li>
<li><a href="/women/shoes/sneakers" aria-current="page">Sneakers</a></li>
</ol>
</nav>
Two details worth calling out for anyone implementing this from a copy-pasted example:
- The
<ol>matters, not just the links inside it. An ordered list is what gives a screen reader the “item 2 of 4” style announcement that conveys hierarchy — a<nav>wrapping bare<a>tags with no list at all restores the landmark and label but still loses the structural signal SC 1.3.1 is asking for. - The current page can stay a real link, or drop the link entirely — the spec allows either.
The APG’s own text is explicit that
aria-currentis only required when the current-page element is a link; if a team instead renders the last breadcrumb item as plain text (a defensible choice, since linking to the page you’re already on serves no function),aria-currentbecomes optional rather than missing a requirement. What to avoid is the common middle ground: ahref="#"dead link with noaria-currentat all, which is both a non-functional link and an unmarked current-page indicator at once.
Handling the visual separators
The > or / characters between breadcrumb items are a CSS concern, not an ARIA one — the pattern
itself says nothing about them, since the <li> boundaries already convey separation
programmatically. The common, defensible approach: render separators with CSS (::before /
::after content, or a background image) rather than as literal characters inside the link text,
so a screen reader reading each list item doesn’t announce a stray “greater than” between every
level. If a separator does need to exist as an actual DOM character for styling reasons, mark it
aria-hidden="true" so it’s skipped by assistive technology while remaining visible on screen.
What a scan catches, and what a person has to check
An automated scanner reliably flags a <div>-based breadcrumb with no link roles at all, and can
often catch a missing aria-label on a <nav> landmark. What it generally can’t verify: whether
aria-current="page" is actually applied to the correct item after a template is reused across
different category depths (a common bug — a shared component defaults to marking the last static
item rather than the true current page), whether truncated link text still carries its full string
as the accessible name, and whether the breadcrumb reads in a sensible order when navigated by
screen reader rather than just looking correct on screen. Confirming those needs a keyboard and a
screen reader pass, not just a check that <nav> and <ol> tags exist somewhere in the markup.
FAQ
Does the breadcrumb <nav> need role="navigation"?
No — <nav> carries the navigation landmark role implicitly in HTML. Adding role="navigation" on
top of a native <nav> element is redundant, not required by the pattern.
What if my breadcrumb has just one or two levels — is it still worth doing this properly?
Yes. The pattern doesn’t have a minimum-depth exception, and a two-level trail (“Home > Sneakers”)
still benefits from the same landmark label and aria-current marking — the implementation cost is
the same regardless of trail length.
Does a breadcrumb replace the need for a page <h1> or other heading structure?
No. A breadcrumb tells a user where they are in the site hierarchy; it isn’t a substitute for a
descriptive page title or heading, and WCAG’s heading-related criteria still apply to the page’s
actual content independently.
Get your navigation checked by a person, not just a parser
Quietramp’s $890 audits include a manual pass through structural navigation components like
breadcrumbs — checking landmark labeling, list semantics, and aria-current accuracy with an
actual screen reader, not just confirming that a <nav> tag exists somewhere in the DOM. See a
real sample report or check pricing.
This is educational content about technical accessibility practice, not legal advice. Meeting WCAG 2.1 AA does not constitute a legal compliance determination under the ADA or any other standard — consult qualified counsel for legal risk questions.
This article was drafted with AI assistance and reviewed by a person for accuracy before publication.