Breadcrumbs
A path trail showing where the current page sits in the site hierarchy.
Last updated
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.
Show codeHide code
<Breadcrumbs items={[
{ label: 'Home', href: '/' },
{ label: 'Products', href: '/products' },
{ label: 'Apogee' },
]} />Add
npx @ava-ui/apogee add breadcrumbs
No Apogee dependencies. Uses @lucide/astro for the chevron separator.
Usage
---
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
Show codeHide code
<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
Show codeHide code
<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
hrefis set) go from faded to full neutral on hover (buttonalso 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".
Show codeHide code
<Breadcrumbs items={[
{ label: 'Home', href: '/' },
{ label: 'Current page' },
]} />Examples
A deep trail wraps instead of overflowing:
Show codeHide code
<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):
Show codeHide code
<Breadcrumbs items={[{ label: 'Dashboard' }]} />Account switcher
A workspace switcher before the trail: a Dropdown whose anchor shows the current account, with radio items.
Show codeHide code
<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) underdir="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.