# Breadcrumbs

> A path trail showing where the current page sits in the site hierarchy.

URL: https://apogee.avaui.dev/docs/breadcrumbs
Last updated: 2026-10-16

A path trail showing where the current page sits in the site hierarchy.

Last updated October 16, 2026

Uses JavaScript

With `maxVisible`, the “…” button reveals the collapsed items and moves focus to the first of them.

**Without JS:** Every item renders and the … button is hidden, so nothing is unreachable.

```astro
<Breadcrumbs items={[
{ label: 'Home', href: '/' },
{ label: 'Products', href: '/products' },
{ label: 'Apogee' },
]} />
```

## Add

```sh
npx @ava-ui/apogee add breadcrumbs
```

No Apogee dependencies. Uses `@lucide/astro` for the chevron separator.

## Usage

```astro
---
import Breadcrumbs from '@/components/apogee/Breadcrumbs/Breadcrumbs.astro'
---
<Breadcrumbs items={[
  { label: 'Home', href: '/' },
  { label: 'Settings' },
]} />
```

## API

`@composable` — exposed to Content Editors in AVA. Any other native `<nav>` attribute passes through.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `{ label: string; href?: string; icon?; ariaLabel? }[]` | — | The trail, in order. An item without `href` (or the last item) renders as plain text. `icon` is a Lucide component shown before the label; with an empty `label` the crumb is icon-only and needs `ariaLabel`. |
| `items[].disabled` | `boolean` | `false` | Renders the item as plain text with `aria-disabled`. |
| `maxVisible` | `number` | — | Show at most this many items: the first, an “…” button that reveals the rest, and the last ones. |
| `expandLabel` | `string` | `'Show all'` | Accessible name of the “…” button (localise it). |
| `variant` | `'text' \| 'button' \| 'line'` | `'text'` | Plain links, small button-like crumbs with the current one filled, or the trail between two rules. |
| `class` | `string` | — | Extra classes on the root `<nav>`, merged last. |

Slot `separator` replaces the chevron between crumbs.

The last item in `items` is always treated as the current page: it renders as a `<span aria-current="page">`, even if it has an `href`.

## Collapsed, separator and disabled

```astro
<Breadcrumbs maxVisible={4} items={[{ label: 'Home', href: '/' }, { label: 'Library', href: '#' }, { label: 'Shelf', href: '#' }, { label: 'Series', href: '#' }, { label: 'Volume', href: '#' }, { label: 'Chapter' }]} />
<Breadcrumbs items={[…]}><span slot="separator">/</span></Breadcrumbs>
<Breadcrumbs items={[{ label: 'Home', href: '/' }, { label: 'Archive', disabled: true }, { label: 'Entry' }]} />
```

## Variants and icons

```astro
<Breadcrumbs variant="button" items={[…]} />
<Breadcrumbs variant="line" items={[…]} />
<Breadcrumbs items={[{ label: '', ariaLabel: 'Home', icon: Home, href: '/' }, { label: 'Projects', icon: Folder, href: '#' }, { label: 'Spring launch' }]} />
```

## States

-   **Hover / focus** — linked crumbs (all but the last, when `href` is set) go from faded to full neutral on hover (`button` also fills); keyboard focus shows a visible ring (`--outline-color-focus`).
-   **Current page** — the last item is bold text, never a link, with `aria-current="page"`.

```astro
<Breadcrumbs items={[
{ label: 'Home', href: '/' },
{ label: 'Current page' },
]} />
```

## Examples

A deep trail wraps instead of overflowing:

```astro
<Breadcrumbs items={[
{ label: 'Home', href: '/' },
{ label: 'Products', href: '/products' },
{ label: 'Design systems', href: '/products/design-systems' },
{ label: 'Apogee', href: '/products/design-systems/apogee' },
{ label: 'Components' },
]} />
```

A single-item trail (just the current page, no links):

```astro
<Breadcrumbs items={[{ label: 'Dashboard' }]} />
```

## Account switcher

A workspace switcher before the trail: a Dropdown whose anchor shows the current account, with radio items.

```astro
<div class="flex items-center gap-2">
<Dropdown id="acct" label="Switch workspace">
  <Button slot="anchor" popovertarget="acct" aria-haspopup="menu" variant="ghost" color="neutral" size="small">
    <Avatar name="Larkspur" size="xsmall" />Larkspur<ChevronsUpDown slot="end" class="size-3.5" />
  </Button>
  <DropdownItem indicator="radio" selected>Larkspur</DropdownItem>
  <DropdownItem indicator="radio">Fernhill</DropdownItem>
</Dropdown>
<span aria-hidden="true">/</span>
<Breadcrumbs items={[…]} />
</div>
```

## Accessibility

| Key | Action |
| --- | --- |
| `Tab` | Moves through the linked crumbs and the “…” button in order. |
| `Enter` | Follows the focused link, or expands the “…” button. |
| `Space` | Expands the hidden crumbs when the “…” button has focus. |

-   Wrapped in `<nav aria-label="Breadcrumb">` so assistive tech can jump to it as a landmark.
-   The trail is a real `<ol>` — order is conveyed to screen readers, not just visually.
-   The current page uses `aria-current="page"`, not a visual cue alone.
-   The separator chevron is `aria-hidden="true"` (decorative) and flips (`rtl:-scale-x-100`) under `dir="rtl"`.

## Tokens

| Token | Used for |
| --- | --- |
| `--foreground-neutral-faded` | Default crumb text |
| `--foreground-neutral` | Hovered crumb + current-page text |
| `--outline-color-focus` | Focus ring on linked crumbs |

## Do / Don’t

-   **Do** end the trail with the current page as plain text, not a link to itself.
-   **Do** keep labels short — this is a navigation aid, not a page title.
-   **Don’t** use Breadcrumbs as the only way to reach a parent page — pair with primary nav.

## Content

-   Labels match the target page’s title (or a shortened form of it), sentence case.
-   No ending punctuation, no separators typed into the label — the component renders the chevron.

## Related

[

PaginationPage links with prev/next and ellipses for long page ranges.

](https://apogee.avaui.dev/docs/pagination)[

NavLinkA navigation link that auto-detects and styles the current route, with prefix matching, external links and a collapsible NavGroup.

](https://apogee.avaui.dev/docs/nav-link)[

StepsA vertical progress list for onboarding, checkout, and wizard flows.

](https://apogee.avaui.dev/docs/steps)
