Skip to content

Breadcrumb

hc-breadcrumb is a pure CSS skin over a standard <nav><ol><li> structure with aria-current="page" on the active step. Separators are injected via CSS ::before so the markup stays free of decorative noise — screen readers ignore generated content by default.

Override --hc-breadcrumb-separator globally (in a stylesheet) or per-instance (inline style) to swap the glyph.

Any CSS content value works — quoted strings, attr(), escaped Unicode, or an inline SVG url() for a fully bespoke marker.

For deep paths, collapse intermediate steps to an ellipsis. Mark the placeholder aria-hidden="true" so screen readers ignore it; keep the truncated steps reachable elsewhere (a navigation menu, the back-button, etc.).

To make the hidden steps reachable, turn the ellipsis into a <button> that opens a hc-menu popover listing them. No new behavior — installMenu() (in the default bundle) wires the trigger automatically: the popovertarget button gets aria-haspopup="menu" / aria-expanded, the popover anchors under it, and arrow keys / Escape work.

Progressive enhancement. The trail collapses gracefully:

  • popovertarget is native HTML — the menu opens on click without JavaScript; installMenu() only adds the anchored placement and keyboard roving.
  • On engines without the popover attribute the menu simply renders inline (the hidden steps stay visible), so the full trail is always in the DOM.

Responsive collapsing. Whether to collapse is a layout decision. Render the full trail by default and switch to the collapsed markup under a width threshold — e.g. set data-collapse on the <nav> and gate the swap with a container query, or render the collapsed form server-side once the path exceeds N levels.

  • The outer <nav aria-label="Breadcrumb"> (or aria-labelledby) gives the landmark a name so assistive tech can skip to or out of it.
  • Use <ol>, not <ul> — the steps have a meaningful order.
  • The current page is not a link: render it as <span aria-current="page"> so it can still receive a visual emphasis without misleading the user into clicking it.
  • Separator glyphs are inserted via CSS ::before. Modern browsers expose pseudo-content to the DOM but exclude it from the accessibility tree by default — no aria-hidden needed on the generated content.
  • Keep link focus outlines. The default sets outline: 2px solid using --hc-color-focus-ring to match the rest of the system.

Component tokens (in component.tokens.json):

Token pathPurpose
breadcrumb.gapSpace between items (and between item and separator).
breadcrumb.font-sizeText size for the whole trail.
breadcrumb.separator-fgColor of the injected separator glyph and the ellipsis.
breadcrumb.link.fg / hover-fgInactive step color, rest and hover.
breadcrumb.current.fg / font-weightActive step appearance.

The custom property --hc-breadcrumb-separator is the override hook for the separator glyph; it has no token entry because the value is a content string rather than a typed design value.

Show the generated CSS variables
--hc-breadcrumb-gap | -font-size | -separator-fg
--hc-breadcrumb-link-fg | -link-hover-fg
--hc-breadcrumb-current-fg | -current-font-weight
--hc-breadcrumb-separator (override hook, no default token)
--hc-color-focus-ring (inherited from data-color)
  • Tabs — for switching between sibling sections.
  • Pagination — for stepping through a sequence of pages.