---
title: Breadcrumb
description: Breadcrumb trail with separator
visibility: guest
draft: false
---

# Breadcrumb

The `<x-wirekit::breadcrumb>` component renders a navigation trail with customizable separators. It follows the [WAI-ARIA Breadcrumb pattern](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/).

## Usage

:::preview{title="Basic Breadcrumb"}
<x-wirekit::breadcrumb schema="false" :items="[
    ['label' => 'Home', 'href' => '/'],
    ['label' => 'Products', 'href' => '/products'],
    ['label' => 'Widget']
]" />
:::

The last item is always rendered as the current page (no link, `aria-current="page"`).

## With Icons

Add an `icon` key to any item to render a decorative glyph before its label
(handy for a leading home icon, or a category icon per crumb). The label stays
the accessible link text — the icon is `aria-hidden` and never reaches the
structured data.

:::preview{title="Breadcrumb with icons"}
<x-wirekit::breadcrumb schema="false" :items="[
    ['label' => 'Home', 'href' => '/', 'icon' => 'home'],
    ['label' => 'Products', 'href' => '/products', 'icon' => 'layers'],
    ['label' => 'Laptop', 'icon' => 'server']
]" />
:::

## Items

Each item can be either an associative array or a plain string:

```blade
{{-- Full form: label + href --}}
['label' => 'Products', 'href' => '/products']

{{-- Short form: label only (rendered without link) --}}
'Products'
```

Items without `href` are rendered as plain `<span>` (no link, no current indicator unless it's the last item).

## Separators

:::preview{title="Separator Variants"}
<x-wirekit::stack gap="sm">
    <x-wirekit::breadcrumb schema="false" :items="[['label' => 'A', 'href' => '/a'], ['label' => 'B', 'href' => '/b'], ['label' => 'C']]" separator="chevron" />
    <x-wirekit::breadcrumb schema="false" :items="[['label' => 'A', 'href' => '/a'], ['label' => 'B', 'href' => '/b'], ['label' => 'C']]" separator="slash" />
    <x-wirekit::breadcrumb schema="false" :items="[['label' => 'A', 'href' => '/a'], ['label' => 'B', 'href' => '/b'], ['label' => 'C']]" separator="arrow" />
    <x-wirekit::breadcrumb schema="false" :items="[['label' => 'A', 'href' => '/a'], ['label' => 'B', 'href' => '/b'], ['label' => 'C']]" separator="dot" />
</x-wirekit::stack>
:::

| Value | Character |
| --- | --- |
| `chevron` (default) | › |
| `slash` | / |
| `arrow` | → |
| `dot` | · |
| custom | any string you pass |

## Structured Data (SEO)

The component automatically renders a [Schema.org BreadcrumbList](https://schema.org/BreadcrumbList) as JSON-LD. Search engines (Google, Bing) use this to display breadcrumb trails directly in search results.

```html
<!-- Rendered automatically — no extra setup needed -->
<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Home", "item": "/" },
        { "@type": "ListItem", "position": 2, "name": "Products", "item": "/products" },
        { "@type": "ListItem", "position": 3, "name": "Widget" }
    ]
}
</script>
```

Items with an `href` get the `item` property (the URL). The last item (current page) typically has no `item` URL, which is [recommended by Google](https://developers.google.com/search/docs/appearance/structured-data/breadcrumb).

::: tip
Validate your breadcrumbs with [Google's Rich Results Test](https://search.google.com/test/rich-results) to ensure they appear correctly in search results.
:::

## More than one breadcrumb on a page

The trail emits its structured data without being asked, which is right for the ordinary case
and wrong the moment a page has two breadcrumbs — a shell's top bar and one in the content body.
Pass `schema="false"` on the second:

```blade
{{-- 1. The shell's top bar carries the canonical trail, and its structured data. --}}
<x-wirekit::shell-bar>
    <x-wirekit::breadcrumb :items="$trail" />
</x-wirekit::shell-bar>

{{-- 2. A second, visual-only copy in the body. Same trail, no competing JSON-LD. --}}
<x-wirekit::breadcrumb :items="$trail" schema="false" />
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `array` | `[]` | Array of items; each is `['label' => .., 'href' => .., 'icon' => ..]` or a plain string |
| `separator` | `string` | `'chevron'` | `'chevron'`, `'slash'`, `'arrow'`, `'dot'`, or any custom string |
| `schema` | `bool` | `true` | Emit BreadcrumbList JSON-LD for this trail. Turn it **off** when the page already carries a breadcrumb elsewhere — a shell's top bar plus one in the content body is the common case. A page must carry exactly one BreadcrumbList; two of them compete rather than combine, and a crawler shown two trails for one URL picks one or neither |
| `scope` | `string\|null` | `null` | Scoped personalization key |

## Accessibility

- Outer `<nav aria-label="Breadcrumb">` — the landmark
- Semantic `<ol>` / `<li>` structure — reads as an ordered list
- Last item marked with `aria-current="page"`
- Separators marked `aria-hidden="true"` so screen readers don't announce "chevron"

## Keyboard Interaction

| Key | Action |
|-----|--------|
| `Tab` | Move focus to the link |
| `Enter` | Activate the link (follow the URL) |

*Each crumb is a link with native browser keyboard semantics.*

## Pitfalls

- **Don't link the current page in the last crumb.** WAI-ARIA Authoring Practices require the trailing crumb to use `aria-current="page"` and render as plain text — the component already enforces this when the last item omits `href`.
- **Don't include more than 5 crumbs.** Cognitive overhead spikes; collapse mid-path with an ellipsis crumb.

## Design Tokens

| Token | Used for |
| --- | --- |
| `--font-wk-body-weight` | Item font weight |
| `--text-wk-sm` | Item font size |
| `--color-wk-text` | Current page item |
| `--color-wk-text-muted` | Inactive ancestor links |
| `--color-wk-text-subtle` | Separator chevron |
| `--color-wk-ring` | Focus ring |
| `--ring-wk-width` | Focus ring width |
| `--radius-wk-sm` | Focus ring radius |
| `--padding-wk-x-xs` | Item horizontal padding |
| `--transition-wk-duration` | Hover transition |

## Config Defaults

The defaults live in `config/wirekit.php` under `components.breadcrumb`. Override them globally:

```php
'components' => [
    'breadcrumb' => ['separator' => 'slash'], // change default separator
],
```

## Further Reading

- [WAI-ARIA Breadcrumb Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/) — the authoring pattern this component implements
- [Schema.org BreadcrumbList](https://schema.org/BreadcrumbList) — the structured data vocabulary used for SEO
- [Google: Breadcrumb Structured Data](https://developers.google.com/search/docs/appearance/structured-data/breadcrumb) — Google's guide to breadcrumb rich results
- [MDN: `aria-current`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current)
- [MDN: `<nav>` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav)
