Breadcrumbs

stable

Breadcrumbs show users where they are within a site hierarchy and let them navigate back to parent sections. The component is CSS-only — no JavaScript required. Colors adapt automatically to any surface or theme context.

Anatomy

Wrap an <ol> in a <nav> with aria-label="Breadcrumb". Each list item gets the .breadcrumb-item class. The current page's link carries aria-current="page". The separator is generated by CSS so it never appears in the DOM or gets read by screen readers.

<nav aria-label="Breadcrumb">
  <ol class="breadcrumb" role="list">
    <li class="breadcrumb-item"><a href="/">Home</a></li>
    <li class="breadcrumb-item"><a href="/components">Components</a></li>
    <li class="breadcrumb-item"><a href="/components/breadcrumbs" aria-current="page">Breadcrumbs</a></li>
  </ol>
</nav>

Usage guidance

Use breadcrumbs when the site has two or more levels of hierarchy and users are likely to have arrived deep in the tree — from search, a direct link, or a previous session. Skip them on flat sites, landing pages, or anywhere the hierarchy has fewer than two meaningful levels.

SituationGuidance
Current page link Keep as an <a> with aria-current="page". Avoid plain <span> — it breaks keyboard navigation consistency.
Depth Show the full path from root. Truncating intermediate crumbs hides context without saving meaningful space.
Placement Render above the page <h1>, below the primary navigation bar.
Mobile .breadcrumb uses flex-wrap: wrap so long paths reflow naturally. If the path is very deep, consider showing only the immediate parent on small viewports.

Accessibility

The correct landmark and ARIA attributes are required — they are not optional polish.

AttributeWhereWhy
aria-label="Breadcrumb" <nav> Distinguishes this nav landmark from the primary navigation when both appear on the same page.
role="list" <ol> Safari/VoiceOver removes list semantics (item count, list navigation) from any <ol> with list-style: none. role="list" restores them regardless of CSS. The <nav> wrapper mitigates this on modern Safari, but role="list" is the robust solution for all versions and wrapper contexts.
aria-current="page" Last <a> Tells screen readers which link represents the current page. Without it, sighted and non-sighted users get different information.
CSS separator ::after pseudo-element Generated via content: '›' / '' — the empty alt value prevents screen readers from announcing the separator character.

CSS reference

Shipped in dist/farn-components.css. Load alongside farn.css or farn-tokens.css. Colors are semantic — they adapt automatically under data-theme and data-surface without any overrides.

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 0.875rem;
}

.breadcrumb-item {
  display: flex;
  align-items: center;
  color: var(--color-text-secondary);
}

.breadcrumb-item:not(:last-child)::after {
  content: '›';        /* fallback: visible in all browsers */
  content: '›' / '';   /* modern: suppresses screen-reader announcement */
  margin: 0 var(--space-xs);
}

.breadcrumb-item a {
  color: inherit;
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out);
}

.breadcrumb-item a:hover,
.breadcrumb-item a[aria-current="page"] {
  color: var(--color-text);
}