Eunomia v1.0.0-beta.2
AllAngularReactNext.jsJavaScriptVue
EunomiaSalmonForestVioletOceanGoldFireCustom…
🇬🇧 English🇫🇷 Français

Breadcrumb

Breadcrumb displays a trail of links tracing the current page's position within a site's hierarchy, from the root down to where someone actually is. The final step always stays a plain label rather than a link, since navigating to the page someone's already on would be redundant.

Dependencies

eun-icon · if using an icon
Overview API Examples Accessibility
Home Catalogue Kitchen mixer tap

When to use

Add a breadcrumb once someone can be more than one level deep in your site, such as a product inside a category or a document inside a folder, so they can always see where they landed and step back without hitting the browser's back button. Skip it on flat, top-level pages where there's nowhere meaningful to trace back to, and never let it be the only way to navigate. It should complement a real primary navigation, not replace one.

Install & usage

Pick a framework in the toolbar above and these snippets adapt.

npm install @eunomia/elements
import "@eunomia/elements/breadcrumb.js";
<eun-breadcrumb aria-label="Breadcrumb">
  <eun-breadcrumb-item href="/">Home</eun-breadcrumb-item>
  <eun-breadcrumb-item href="/catalogue">Catalogue</eun-breadcrumb-item>
  <eun-breadcrumb-item current>Kitchen mixer tap</eun-breadcrumb-item>
</eun-breadcrumb>

Importing the file registers <eun-breadcrumb> and <eun-breadcrumb-item> as custom elements, with no further setup needed. It works with any framework, or none, since they're standard web components. One thing to remember is current on the last step, since eun-breadcrumb-item has no way to know on its own that it's the last of its siblings, and never infers that state for you (see the Accessibility tab).

Guidance

  • Use eun-breadcrumb on any page nested more than one level deep, so people can see where they are and jump back to an ancestor page in one click
  • Always mark the trail's actual last step with current, since eun-breadcrumb-item never infers it from position (see the Accessibility tab)
  • Keep labels short, since long ones truncate with an ellipsis past --breadcrumb-item-max-width (see the Examples tab)
  • Pair the icon prop with visible text on a eun-breadcrumb-item step, since an icon alone has no accessible name (see the Accessibility tab)
  • Using it on top-level pages, since a one- or two-step trail rarely earns its place
  • Setting href on the step marked current and expecting it to still link. current always wins, rendering unlinked text regardless, since linking to the page someone's already on is a confusing, redundant control
  • Using it as the page's only means of navigating back. Pair it with a proper primary navigation, not instead of one

Live testing

Properties

eun-breadcrumb mostly just needs aria-label (defaults to "Breadcrumb") and its eun-breadcrumb-item children. items below is the data-driven alternative (see "Data-driven trail" in the Examples tab).

Breadcrumb <eun-breadcrumb>

Attributes

NameTypeDefaultDescription
aria-labelstring'Breadcrumb'The accessible label for the navigation landmark
itemsArray<EunomiaBreadcrumbItemData>[]The trail's steps, in order, from the root to the current page. Each entry may set a label, an href, and an optional leading icon

Import the exact TypeScript type behind any property above, see Types.

Slots

NameDescription
(default)Breadcrumb item elements, used instead of or alongside items

CSS custom properties

NameDescription
--breadcrumb-link-colorSets the color of linked steps
--breadcrumb-link-color-hoverSets the color of linked steps on hover or focus
--breadcrumb-current-colorSets the color of the current page and unlinked steps
--breadcrumb-focus-outline-colorSets the color of a linked step's focus outline
--breadcrumb-separatorSets the separator between steps, as a quoted CSS string, such as '>'
--breadcrumb-separator-colorSets the color of the separator
--breadcrumb-separator-gapSets the gap around the separator
--breadcrumb-item-max-widthSets the maximum width of each step, beyond which its label truncates with an ellipsis
--breadcrumb-gapSets the row gap, used when the trail wraps onto multiple lines
--breadcrumb-transition-durationSets the duration of the link hover color transition

Into an item

Breadcrumb item <eun-breadcrumb-item>

Attributes

NameTypeDefaultDescription
hrefstringThe URL this step links to. Renders as plain, unlinked text when unset, such as a category that groups pages but isn't itself a page
currentbooleanfalseMarks this as the trail's current, unlinked page, regardless of href
iconEunomiaIconNameAn optional leading icon shown before the slotted label. Purely decorative, so it never substitutes for the label's own visible text

Import the exact TypeScript type behind any property above, see Types.

Slots

NameDescription
(default)The step's label content
iconReplaces the leading icon entirely with any content, not just an icon element. Falls back to icon when empty

Basic

Home Catalogue Kitchen mixer tap
<eun-breadcrumb aria-label="Breadcrumb">
  <eun-breadcrumb-item href="/">Home</eun-breadcrumb-item>
  <eun-breadcrumb-item href="/catalogue">Catalogue</eun-breadcrumb-item>
  <eun-breadcrumb-item current>Kitchen mixer tap</eun-breadcrumb-item>
</eun-breadcrumb>

Two steps

Home Catalogue
<eun-breadcrumb aria-label="Breadcrumb">
  <eun-breadcrumb-item href="/">Home</eun-breadcrumb-item>
  <eun-breadcrumb-item current>Catalogue</eun-breadcrumb-item>
</eun-breadcrumb>

Unlinked intermediate step

A step with neither href nor current renders as plain text instead of a link, useful for a category that groups pages without being a page (or the current page) itself.

Home Faucets Kitchen mixer tap
<eun-breadcrumb aria-label="Breadcrumb">
  <eun-breadcrumb-item href="/">Home</eun-breadcrumb-item>
  <eun-breadcrumb-item>Faucets</eun-breadcrumb-item>
  <eun-breadcrumb-item current>Kitchen mixer tap</eun-breadcrumb-item>
</eun-breadcrumb>

Long labels truncate

Each step's label truncates with an ellipsis past --breadcrumb-item-max-width (240px by default), so one long label can't push the trail off-screen.

Home A surprisingly long category name that needs truncating Kitchen mixer tap

Custom separator

--breadcrumb-separator takes any quoted CSS string.

Home Catalogue Kitchen mixer tap
<eun-breadcrumb aria-label="Breadcrumb" style="--breadcrumb-separator: '>';">
  ...
</eun-breadcrumb>

With an icon

The icon prop renders a leading icon before the label, using eun-icon under the hood. Its module must still be imported alongside breadcrumb whenever a step sets it, as shown below (see the dependency badge above). An icon should always be paired with visible text, since an icon-only step has no accessible name (see the Accessibility tab).

Home Catalogue
import "@eunomia/elements/icon.js";
<eun-breadcrumb-item href="/" icon="home">Home</eun-breadcrumb-item>

Custom icon markup

The default slot still accepts any content, so slotting an icon by hand works too, alongside (or instead of) the icon prop above. Reach for it when a step needs something the prop can't express, such as a different icon size or an entirely different icon component.

Home Catalogue
<eun-breadcrumb-item href="/">
  <eun-icon name="home" size="18"></eun-icon>
  Home
</eun-breadcrumb-item>

It needs the same import as the icon prop above, since eun-icon must be registered for either approach to render anything.

Custom icon, via the icon slot

Need something other than a eun-icon, or a different icon library entirely, without mixing it into the label text itself? Slot your own content into the dedicated icon slot instead — it replaces the prop-driven icon entirely and is kept visually separate from the label.

Home Catalogue
<eun-breadcrumb-item href="/">
  <svg
    slot="icon"
    width="14"
    height="14"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    stroke-width="2"
  >
    <path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"></path>
  </svg>
  Home
</eun-breadcrumb-item>

Custom

Override the --breadcrumb-* CSS variables, listed in full in the API tab.

Home Catalogue Kitchen mixer tap
<eun-breadcrumb class="custom-breadcrumb" aria-label="Breadcrumb">
  ...
</eun-breadcrumb>
.custom-breadcrumb {
  --breadcrumb-link-color: #be185d;
  --breadcrumb-link-color-hover: #9d174d;
  --breadcrumb-separator: ">";
}

Data-driven trail

An alternative to writing out eun-breadcrumb-item children by hand. Set items to an array and eun-breadcrumb renders the whole trail itself, including which step counts as current. Each entry can set a label, an href, and an optional leading icon, so it's well suited to a trail built from route data (e.g. inside a router-integrated layout). Reach for slotted eun-breadcrumb-items instead once a step needs richer content than that.

Unlike eun-breadcrumb-item's own explicit current, the last entry in items is always rendered as the current, unlinked page, regardless of whether it has an href. eun-breadcrumb knows its own array's length, so it can infer that for you here, while a standalone eun-breadcrumb-item has no equivalent way to know it's the last of its siblings, which is exactly why it needs current set explicitly instead (see the Accessibility tab). An intermediate entry without an href still renders as plain, unlinked text either way.

<eun-breadcrumb aria-label="Breadcrumb"></eun-breadcrumb>
document.querySelector("eun-breadcrumb").items = [
  { label: "Home", href: "/", icon: "home" },
  { label: "Catalogue", href: "/catalogue" },
  { label: "Kitchen mixer tap" },
];

Keyboard interactions

eun-breadcrumb adds no custom keyboard handling of its own. Every step is a native <a> (or plain text), so standard link navigation already applies:

Key Action
Tab / Shift+Tab Moves focus between linked steps, in trail order
Enter Follows the focused step's link

Aria attributes and rules

  • Rendered as <nav aria-label="Breadcrumb"> wrapping an <ol role="list">, the standard breadcrumb pattern recommended by the WAI-ARIA APG. Override aria-label for other languages/contexts.
  • role="list" is set explicitly despite <ol> having it implicitly: Safari drops the implicit role once list-style: none is applied (needed here for the visual flex layout), which would otherwise silently skip the list for VoiceOver users.
  • The current step is a <span aria-current="page">, never a link, even if it happens to carry an href, since linking to the page someone's already on adds a confusing, redundant control.
  • Steps without an href render as plain text (not a disabled-looking link), since they aren't pages of their own.

current is explicit, on purpose

A standalone eun-breadcrumb-item has no way to know it's the last of its siblings, unlike eun-breadcrumb's own items array, where the array's length already tells it which entry is last. Omitting href alone isn't equivalent to current. Without it, a eun-breadcrumb-item with no href renders as plain unlinked text but without aria-current="page", indistinguishable, to a screen reader, from an unlinked intermediate category like "Faucets" in the example above. Set current explicitly on whichever step is genuinely the trail's current page.

Label accessibility

A step's accessible name comes entirely from its content, whether plain text or whatever's slotted into a eun-breadcrumb-item. An icon-only step has no accessible name, since the icon prop renders eun-icon with aria-hidden="true" by design (see the Icon component), and content-based naming has nothing else to fall back to. Always pair an icon with visible text (see "With an icon" above), or set aria-label directly on the eun-breadcrumb-item if the text truly can't be visible. It's forwarded straight to its inner link/text, not left stranded on the outer element alone.

Long labels

Labels truncate visually past --breadcrumb-item-max-width, but the full text stays in the DOM. Screen readers always read the complete label, regardless of how much of it is visually clipped.

Reference links

WAI-ARIA Authoring Practices: Breadcrumb Pattern
WAI Web Accessibility Tutorials: Labeling Controls