Breadcrumb
Show where a page sits in your site and link back to its parent pages.
import { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a breadcrumb when pages nest several levels deep, like a workspace, a project, a section and an item, and people need to step back up. Don't use it as the main navigation, on a flat site, or to show progress through the steps of a task. It describes where a page lives, not how someone got there.
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '@youj/react'
export function DeploymentBreadcrumb() {
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/acme">Acme</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/acme/web">web</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Deployments</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}The current page is a BreadcrumbPage: plain text marked aria-current="page", not a link to itself. Crumbs can lead with an icon or a logo, and labels longer than 12rem truncate with an ellipsis. The full text stays in the link's accessible name.
To render your router's link, pass it through render. It keeps the crumb's look and focus ring:
import Link from 'next/link'
<BreadcrumbLink render={<Link href="/acme/web" />}>web</BreadcrumbLink>Description
A path from an organization down to a deployment, ending on the current page.
A long path folded into an ellipsis button that unfolds the hidden crumbs.
Give the list maxItems and a path longer than that folds its middle crumbs into an ellipsis button, named for what it holds ("Show 3 more"). Pressing it unfolds the crumbs in place and moves focus to the first one it revealed. itemsBeforeCollapse (default 1) and itemsAfterCollapse (default 2, the page and its parent) choose what stays visible. A new path starts folded again.
When crumbs come from data, return each crumb with the separator after it, in a fragment or a small component, and the list folds them as one unit.
A chevron in place of the default separator, and a static ellipsis.
BreadcrumbSeparator draws a slanted hairline by default. Pass any mark as its children instead, such as a chevron. A static BreadcrumbEllipsis marks a gap the app decided not to show, and it isn't interactive.
Code
breadcrumb-demo.tsx, the Demo story. The component itself comes from the package.
Reference
PropsmaxItems, itemsBeforeCollapse, itemsAfterCollapse (3)
Props
BreadcrumbList
| Prop | Type | |
|---|---|---|
maxItems | numberCollapse the middle crumbs when there are more than this many. | – |
itemsBeforeCollapse | numberCrumbs kept before the ellipsis. default 1 | 1 |
itemsAfterCollapse | numberCrumbs kept after the ellipsis. default 2 | 2 |
Other props pass through: extends ComponentProps<'ol'>. | ||
Other parts
Breadcrumb is a nav, BreadcrumbItem and BreadcrumbSeparator are li elements, and BreadcrumbPage is a span. Each takes the props of its element. BreadcrumbLink and BreadcrumbEllipsis also take render, to swap the element they render.
BreadcrumbLink adds no props of its own. They pass through to useRender.ComponentProps<'a'>.
MotionUnfold, width, unfold, fade, fade offset… · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Unfold, widtheach folded crumb grows from zero, so the ones after it glide aside | duration.baseease.standard220ms · cubic-bezier(0.2, 0, 0, 1) | 220mscubic-bezier(0.2, 0, 0, 1) | |
| Unfold, fadeeach crumb fades in once its width is under way | duration.baseease.enter220ms · cubic-bezier(0.16, 1, 0.3, 1) | 220mscubic-bezier(0.16, 1, 0.3, 1) | |
| Fade offsetfrom a crumb’s width to its fade | stagger.base40ms step | 40ms step | |
| Cascadefrom one unfolding crumb to the next | stagger.tight24ms step | 24ms step | |
| Link coloron hover | duration.fastease.standard140ms · cubic-bezier(0.2, 0, 0, 1) | 140mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
Folded crumbs appear at once, in place. Links change color without easing.
A crumb clips only while it grows. Once it has unfolded, the clip comes off, so its focus ring has room.
Reduced motion
The folded crumbs appear at once when the ellipsis is pressed, and focus still moves to the first of them. Nothing else changes.
AccessibilityKeyboard, ARIA, focus
Accessibility
Breadcrumbis anavlandmark named "Breadcrumb". If a page has more than one, give each its ownaria-label.- The crumbs are an ordered list. Separators are
role="presentation"andaria-hidden, so the list announces only the crumbs. - The current page carries
aria-current="page"and isn't a link. - The fold is a real button named for the crumbs it holds. It unfolds on Enter or Space, and focus moves to the first crumb it reveals, so keyboard users don't lose their place.
- An icon-only crumb needs an
aria-label, like the home link in the separators example.