Canvas Design System
Main Site Tokens

Breadcrumb

Shows where the current page sits in the hierarchy, and gives one-click routes back up it.

When to Use

Use when: The page sits two or more levels deep in a real hierarchy readers navigate — a workshop inside a category inside the library. Breadcrumbs answer "where am I" and "how do I get back up".
Don't use when: The page is top-level, or the "hierarchy" is really a linear flow — a wizard needs Progress, not a trail. Don't use it to record how the reader arrived; it reflects structure, not history.

Variants

There's one visual treatment. What changes is depth — and the only structural rule is that the final item has no href, because it's the page you're on.

Two levels

Three levels

<?= ws_breadcrumb([
    ['label' => 'Home', 'href' => '/'],
    ['label' => 'Workshops', 'href' => '/library/workshops/'],
    ['label' => 'Design Sprint'],
]) ?>

Deep nesting

Four levels is the practical ceiling. Past that, shorten the labels or reconsider the information architecture — the trail wraps and stops being scannable.

Custom separator

Any Material icon name works. Change it only for a deliberate reason — the chevron is the platform default and consistency is worth more than novelty.

<?= ws_breadcrumb($items, ['separator' => 'arrow_forward_ios']) ?>

States

StateBehavior
Ancestor linkRendered as an <a class="ws-breadcrumb__link"> in --text-muted.
HoverLink shifts to --mainsite-primary over --transition-fast.
FocusNative browser focus ring on the anchor — the component adds no custom outline.
Current pageThe last item is emitted as <span class="ws-breadcrumb__text"> inside an item marked .ws-breadcrumb__item--current, carrying aria-current="page". It's deliberately not a link.
Item with no hrefAny item can omit href, not just the last — it renders as plain text. Use this for a real but unlinkable tier, such as a grouping that has no index page.

Real-World Usage

A library exercise page builds the trail from the record's own category, so the breadcrumb tracks the data rather than being hand-written per page.

<?= ws_breadcrumb([
    ['label' => 'Home',      'href' => '/'],
    ['label' => 'Exercises', 'href' => '/library/exercises/'],
    ['label' => $ex['category_name'],
     'href'  => '/library/exercises/?category=' . urlencode($ex['category_slug'])],
    ['label' => $ex['name']],
]) ?>

Options

OptionTypeDefaultPurpose
$itemsarrayrequiredPositional. Ordered list of ['label' => …, 'href' => …], root first. Omit href on the last item.
separatorstring'chevron_right'Material icon name rendered between items
idstringnullElement ID
classstring''Additional CSS classes

Item options

KeyTypeDefaultPurpose
labelstringVisible text. Keep it to the noun — "Exercises", not "All exercises in the library".
hrefstringnullDestination. Omit to render the item as plain text.

Accessibility

This is one of the better-wired components in the set — it follows the WAI-ARIA Breadcrumb pattern as shipped.

ConcernBehavior
LandmarkWrapped in <nav aria-label="Breadcrumb">, so it's reachable as a named landmark and distinguishable from other navs on the page.
StructureAn ordered <ol>, so screen readers announce position and count — "3 of 4".
Current pageThe final item carries aria-current="page" and is not a link, so it isn't announced as an actionable destination.
KeyboardAncestor links are standard anchors in Tab order, activated with Enter. Nothing custom.
SeparatorsDecorative icons between items. Keep them out of the accessible name — never encode meaning in the separator alone.
ContrastAncestors use --text-muted against the page surface; the current item uses --text-dark. The current item is intentionally the highest-contrast element.

Tokens

TokenUsed for
--text-mutedAncestor link colour
--text-dark / --text-defaultCurrent-page text
--mainsite-primaryLink hover colour
--gray-400Separator icon
--space-1Gap between item, separator, and next item
--text-body / --text-metaLabel type scale
--font-body / --font-mediumFace, and the weight bump on the current item
--transition-fastLink hover

CSS Classes

ClassPurpose
.ws-breadcrumbThe <nav> wrapper
.ws-breadcrumb__listThe <ol>
.ws-breadcrumb__itemEach <li>
.ws-breadcrumb__item--currentThe final item
.ws-breadcrumb__linkAncestor anchor
.ws-breadcrumb__textNon-link label (current page, or any item without href)
.ws-breadcrumb__separatorSeparator icon

Files

FilePurpose
includes/components/helpers.phpws_breadcrumb() helper function
includes/components/breadcrumb.phpTemplate — list markup and ARIA wiring
includes/components/components.cssStyles (.ws-breadcrumb rules)