Breadcrumb
Displays the path to the current resource using a hierarchy of links; a crumb takes an icon, or is icon-only with an accessible label.
Preview
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Home') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Components') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
Installation
php artisan ui:add breadcrumb
Registry contract
php artisan ui:add breadcrumb
writes only the files below. The CLI validates each file hash before writing and asks before it replaces a local change, unless you pass --force.
-
resources/views/components/ui/breadcrumb.blade.php -
resources/views/components/ui/breadcrumb/list.blade.php -
resources/views/components/ui/breadcrumb/item.blade.php -
resources/views/components/ui/breadcrumb/link.blade.php -
resources/views/components/ui/breadcrumb/page.blade.php -
resources/views/components/ui/breadcrumb/separator.blade.php -
resources/views/components/ui/breadcrumb/ellipsis.blade.php
- Registry dependencies
- None — installs on its own.
- Packages
-
composer: jml/brok:^0.2
Use with AI
A brief for your coding agent: install command, usage, props, guidance and the rules. Copy it, or open a prompt about this component in an assistant.
# Brok UI: Breadcrumb (`breadcrumb`)
Displays the path to the current resource using a hierarchy of links; a crumb takes an icon, or is icon-only with an accessible label.
Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.
## Install
```bash
php artisan ui:add breadcrumb
```
## Usage
```blade
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Home') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Components') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
```
## Props
- `href` (string, default `#`) — Declared by @props in the registry Blade source.
- `icon` (mixed|null, default `null`) — Declared by @props in the registry Blade source.
- `label` (mixed|null, default `null`) — Declared by @props in the registry Blade source.
## Use when
- Use to orient users and help them move across pages, sections, or commands.
- Showing the hierarchical path from the site root or section down to the current page.
- Letting users jump back to any ancestor page, especially in deep navigation structures.
## Avoid when
- Do not hide primary wayfinding in novelty interactions or deep nested structures if straightforward navigation would be clearer.
- The current page has no meaningful ancestor hierarchy, such as a flat top-level page.
- The sequence represents steps in a process rather than a location; use a stepper or progress indicator instead.
## Anti-patterns
- Hiding primary wayfinding in novelty interactions
## Rules
- Use the `<brok:breadcrumb>` tag (or `<x-ui.breadcrumb>`) in Blade; do not rewrite the component.
- Prefer the documented props and variants over utility-class overrides; when a utility must win, use the `!` important modifier.
- Use semantic design tokens (`bg-primary`, `text-muted-foreground`), never raw colour utilities.
- Keep the `data-slot` attributes; they are the styling and test hooks.
## Links
- Docs: https://brokui.dev/docs/components/breadcrumb
- Registry JSON (files, props, contract): https://brokui.dev/r/open/breadcrumb.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
Examples
Custom Separator
<div class="flex flex-col gap-4">
{{-- Slash separator --}}
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Home') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator>/</x-ui.breadcrumb.separator>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Docs') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator>/</x-ui.breadcrumb.separator>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
{{-- Dot separator --}}
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Home') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="2" />
</svg>
</x-ui.breadcrumb.separator>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Docs') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="2" />
</svg>
</x-ui.breadcrumb.separator>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
{{-- Arrow separator (mirrors under RTL) --}}
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Home') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="rtl:-scale-x-100" aria-hidden="true">
<path d="M5 12h14" />
<path d="m12 5 7 7-7 7" />
</svg>
</x-ui.breadcrumb.separator>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Docs') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="rtl:-scale-x-100" aria-hidden="true">
<path d="M5 12h14" />
<path d="m12 5 7 7-7 7" />
</svg>
</x-ui.breadcrumb.separator>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
</div>
Responsive Collapse
{{-- Middle items collapse to an ellipsis on small screens and expand on sm: and up. --}}
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Home') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
{{-- Compact: shown only below sm --}}
<x-ui.breadcrumb.item class="sm:hidden">
<x-ui.breadcrumb.ellipsis />
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator class="sm:hidden" />
{{-- Full: hidden below sm --}}
<x-ui.breadcrumb.item class="hidden sm:inline-flex">
<x-ui.breadcrumb.link href="#">{{ __('Components') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator class="hidden sm:flex" />
<x-ui.breadcrumb.item class="hidden sm:inline-flex">
<x-ui.breadcrumb.link href="#">{{ __('Navigation') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator class="hidden sm:flex" />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
With Dropdown
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Home') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
{{-- Collapsed middle items, revealed via a dropdown menu --}}
<x-ui.dropdown>
<x-ui.dropdown.trigger class="gap-1" aria-label="{{ __('Toggle menu') }}">
<x-ui.breadcrumb.ellipsis />
</x-ui.dropdown.trigger>
<x-ui.dropdown.content align="start">
<x-ui.dropdown.item href="#">{{ __('Documentation') }}</x-ui.dropdown.item>
<x-ui.dropdown.item href="#">{{ __('Themes') }}</x-ui.dropdown.item>
<x-ui.dropdown.item href="#">{{ __('GitHub') }}</x-ui.dropdown.item>
</x-ui.dropdown.content>
</x-ui.dropdown>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Components') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
With Ellipsis
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Home') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.ellipsis />
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Components') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
With Home
{{-- An icon-only crumb: give `icon` and `label`, leave the slot empty. --}}
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#" label="{{ __('Home') }}">
<x-slot:icon><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 9.5 12 3l9 6.5" /><path d="M5 10v10h14V10" /></svg></x-slot:icon>
</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">{{ __('Components') }}</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>{{ __('Breadcrumb') }}</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
With Icons
<x-ui.breadcrumb>
<x-ui.breadcrumb.list>
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">
<x-slot:icon><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 9.5 12 3l9 6.5" /><path d="M5 10v10h14V10" /></svg></x-slot:icon>
{{ __('Home') }}
</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.link href="#">
<x-slot:icon><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" /><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" /></svg></x-slot:icon>
{{ __('Docs') }}
</x-ui.breadcrumb.link>
</x-ui.breadcrumb.item>
<x-ui.breadcrumb.separator />
<x-ui.breadcrumb.item>
<x-ui.breadcrumb.page>
<x-slot:icon><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><path d="M14 2v6h6" /></svg></x-slot:icon>
{{ __('Breadcrumb') }}
</x-ui.breadcrumb.page>
</x-ui.breadcrumb.item>
</x-ui.breadcrumb.list>
</x-ui.breadcrumb>
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| href | string | # | Declared by @props in the registry Blade source. |
| icon | mixed | null | null | Declared by @props in the registry Blade source. |
| label | mixed | null | null | Declared by @props in the registry Blade source. |
Slots
default— breadcrumb.item elements composing the trail, separated by breadcrumb.separator.x-ui.breadcrumb.list— Installed subcomponent from the registry item.x-ui.breadcrumb.item— Installed subcomponent from the registry item.x-ui.breadcrumb.link— Installed subcomponent from the registry item.x-ui.breadcrumb.page— Installed subcomponent from the registry item.x-ui.breadcrumb.separator— Installed subcomponent from the registry item.x-ui.breadcrumb.ellipsis— Installed subcomponent from the registry item.
Data slots
Stable hooks for CSS overrides and browser tests.
Behavior
- Every crumb except the current page renders as a real link; the current page renders as non-interactive text.
- An ellipsis crumb can collapse a long middle section of the trail, optionally opening a dropdown of the hidden ancestors.
- Declares registry capability flags: a11y, responsive, rtl, darkMode, localized.
Guidance
Orient users and move between destinations.
Use when
- Use to orient users and help them move across pages, sections, or commands.
- Showing the hierarchical path from the site root or section down to the current page.
- Letting users jump back to any ancestor page, especially in deep navigation structures.
Avoid when
- Do not hide primary wayfinding in novelty interactions or deep nested structures if straightforward navigation would be clearer.
- The current page has no meaningful ancestor hierarchy, such as a flat top-level page.
- The sequence represents steps in a process rather than a location; use a stepper or progress indicator instead.
Use instead
- Visible links and local navigation
Anti-patterns
- Hiding primary wayfinding in novelty interactions
- Anatomy
- Theming hooks
Accessibility
- Keyboard
- native
- Focus
native
- The root is a nav landmark labelled as breadcrumb navigation, and the current page is marked aria-current="page" instead of relying on styling alone.
- An icon-only crumb requires the label prop so it always has an accessible name.
- Semantic HTML and a stable
data-slotattribute for styling and scripting hooks. - Focus-visible rings use the
ringtoken, so keyboard focus is always visible. - Disabled and invalid states are conveyed to assistive tech, not by color alone.
- Targets WCAG 2.2 AA; verify contrast in light, dark, admin and customer surfaces in the preview.
- Labels go through
__()and layout uses logical properties (ms-*,text-start), so it mirrors underdir="rtl"— flip the preview to RTL to confirm. - Dark mode uses the same semantic tokens under the
darkclass; high contrast follows forced-color system tokens.
Livewire
Livewire can update this component through forwarded wire:* attributes.
Validation
Validation support: native. Keep the error message connected with aria-describedby.
<form wire:submit="save" class="space-y-2">
<brok:breadcrumb
wire:model="value"
:aria-invalid="$errors->has('value') ? 'true' : 'false'"
aria-describedby="value-error"
/>
@error('value')
<p id="value-error" role="alert">{{ $message }}</p>
@enderror
<brok:button type="submit" wire:loading.attr="disabled">
<span wire:loading.remove>Save</span>
<span wire:loading>Saving…</span>
</brok:button>
</form>
Source
The exact, editable files ui:add writes
into your app. Previews render this same code; there are no preview-only components.
<nav aria-label="{{ __('breadcrumb') }}" data-slot="breadcrumb" {{ $attributes }}>{{ $slot }}</nav>
<ol data-slot="breadcrumb-list" {{ $attributes->merge(['class' => 'flex flex-wrap items-center gap-2 break-words text-sm text-muted-foreground sm:gap-2']) }}>{{ $slot }}</ol>
<li data-slot="breadcrumb-item" {{ $attributes->merge(['class' => 'inline-flex items-center gap-2']) }}>{{ $slot }}</li>
@props([
'href' => '#',
// Optional leading icon (an <svg>). With an empty default slot the crumb is
// icon-only: `label` becomes its accessible name and the icon fills the row.
'icon' => null,
'label' => null,
])
@php
$iconOnly = $icon !== null && trim((string) $slot) === '';
$layout = $icon !== null ? ' inline-flex items-center gap-2' : '';
@endphp
<a
href="{{ $href }}"
data-slot="breadcrumb-link"
@if ($iconOnly) data-icon-only="true" @endif
@if ($iconOnly && $label) aria-label="{{ $label }}" @endif
{{ $attributes->merge(['class' => 'transition-colors hover:text-foreground motion-reduce:transition-none'.$layout]) }}
>
@if ($icon)
<span class="shrink-0 [&>svg]:size-4" aria-hidden="true">{{ $icon }}</span>
@endif
@if ($iconOnly && $label)<span class="sr-only">{{ $label }}</span>@else{{ $slot }}@endif
</a>
@props([
// Optional leading icon (an <svg>). With an empty default slot the current
// page is icon-only and `label` is read out instead.
'icon' => null,
'label' => null,
])
@php
$iconOnly = $icon !== null && trim((string) $slot) === '';
$layout = $icon !== null ? ' inline-flex items-center gap-2' : '';
@endphp
<span
data-slot="breadcrumb-page"
role="link"
aria-disabled="true"
aria-current="page"
@if ($iconOnly) data-icon-only="true" @endif
@if ($iconOnly && $label) aria-label="{{ $label }}" @endif
{{ $attributes->merge(['class' => 'font-normal text-foreground'.$layout]) }}
>
@if ($icon)
<span class="shrink-0 [&>svg]:size-4" aria-hidden="true">{{ $icon }}</span>
@endif
@if ($iconOnly && $label)<span class="sr-only">{{ $label }}</span>@else{{ $slot }}@endif
</span>
<li data-slot="breadcrumb-separator" role="presentation" aria-hidden="true" {{ $attributes->merge(['class' => '[&>svg]:size-4']) }}>
@if (trim($slot) === '')
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="rtl:-scale-x-100">
<path d="m9 18 6-6-6-6" />
</svg>
@else
{{ $slot }}
@endif
</li>
<span data-slot="breadcrumb-ellipsis" role="presentation" aria-hidden="true" {{ $attributes->merge(['class' => 'flex size-9 items-center justify-center']) }}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4">
<circle cx="12" cy="12" r="1" />
<circle cx="19" cy="12" r="1" />
<circle cx="5" cy="12" r="1" />
</svg>
<span class="sr-only">{{ __('More') }}</span>
</span>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.2.2 - Status
- Stable
- License
-
open - Accessibility reviewed
- No review date recorded
- Last breaking change
- No date recorded
- Deprecation
- Not deprecated
- Contract
-
v6 - Foundation
-
≥ 1.0.0