Navigation
Breadcrumb
Gliding hover pill with animated trail expansion
detent-breadcrumb
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 2
- Wave
- phase-2-navigation
- Group
- Navigation
5.4 KB gzip for the class module · inlines the shared spring
Variants
Recorded states
hoverrecorded state; no settercollapsedrecorded state; no setter
Usage
Import
import '/components/breadcrumb/define.js';
// or register it yourself
import { DetentBreadcrumb } from '/components/breadcrumb/breadcrumb.js';
Attributes
max-itemsseparator
Properties
itemsseparatormaxItemsasexpanded
Slots
No slots are recorded for this component.
Events
No events are recorded for this component.
Example
Runnable example: site/examples/breadcrumb.ts. The snippet below is generated from the catalogued attributes.
<detent-breadcrumb
max-items="4"
separator="chevron"
></detent-breadcrumb>
Property-only values
const element = document.querySelector('detent-breadcrumb');
if (element !== null) {
// items: BreadcrumbItem[]
element.items = [];
// as: React.ElementType
element.as = 'a';
}
Source
The pinned upstream source for this row:
src/components/ui/breadcrumb.tsxsha256 585c49067eba…
Native files
The native module and its artifacts:
src/components/breadcrumb/breadcrumb.tssrc/components/breadcrumb/styles.csssrc/components/breadcrumb/define.tsdocs/components/breadcrumb.mdsite/examples/breadcrumb.tstests/browser/breadcrumb.spec.tsevidence/components/breadcrumb.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
max-items | maxItems | number | 4 | Kebab-case attribute; camelCase property. |
separator | separator | 'chevron' | 'slash' | 'chevron' | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
items | BreadcrumbItem[] | undefined | Property-only: assign from script; not accepted as an attribute. |
separator | 'chevron' | 'slash' | 'chevron' | Property-only: assign from script; not accepted as an attribute. |
maxItems | number | 4 | Property-only: assign from script; not accepted as an attribute. |
as | React.ElementType | 'a' | Property-only: assign from script; not accepted as an attribute. |
expanded | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
Events
No custom events are recorded for this component.
Slots
No slots are recorded for this component.
CSS customisation
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- `as` accepts a tag name ('a' default, e.g. 'my-router-link') - a React element type or constructor has no native equivalent.
- `maxItems` is clamped to >= 2, unparsable becomes 4, and the read-only `maxItems` getter reports the resolved value.
- The hover pill uses the upstream source's code-local spring (500/40/0.6) through the shared spring helper, not one of the recorded motionTokens.
- `ChevronRight`/`Ellipsis` become a local decorative SVG and a text glyph in a labelled button; the reveal is a CSS keyframe removed under reduced motion.
- Upstream's hard-coded neutral-* pairs become --detent-color-* and the separator keeps 3:1+ (accessibility correction); an `items` write collapses the trail again.
- `part="link"` also marks a crumb that is not a link (`<span data-static="true">`); only items with `href` render an `<a>`/`as` element.
What it does
A navigation trail with a gliding hover pill, an ellipsis trigger that expands a collapsed middle with focus transfer, and chevron or slash separators.
Upstream behaviour
- Hover pill smoothly glides between links using Framer Motion layoutId
- Long trails collapse the middle items into an ellipsis trigger button
- Clicking ellipsis animates hidden crumbs in while focus transfers to the first revealed crumb
- Supports chevron or slash separator styles and custom router link components (Next.js Link or <a>)
- Full accessibility with aria-label="Breadcrumb", aria-current="page", and keyboard navigation
Differences from upstream
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- `as` accepts a tag name ('a' default, e.g. 'my-router-link') - a React element type or constructor has no native equivalent.
- `maxItems` is clamped to >= 2, unparsable becomes 4, and the read-only `maxItems` getter reports the resolved value.
- The hover pill uses the upstream source's code-local spring (500/40/0.6) through the shared spring helper, not one of the recorded motionTokens.
- `ChevronRight`/`Ellipsis` become a local decorative SVG and a text glyph in a labelled button; the reveal is a CSS keyframe removed under reduced motion.
- Upstream's hard-coded neutral-* pairs become --detent-color-* and the separator keeps 3:1+ (accessibility correction); an `items` write collapses the trail again.
- `part="link"` also marks a crumb that is not a link (`<span data-static="true">`); only items with `href` render an `<a>`/`as` element.