Breadcrumb
Where the page sits in the hierarchy: one line of caps crumbs, the LTA staircase in the section bar, or a single parent link.
import { Breadcrumb } from '@fairgarden-private/design/components/Breadcrumb'
Pass the ancestors root first as items and the page's own title as current. The current page comes last, unlinked, heavier and marked aria-current="page"; ancestors are --role-muted at weight 400, and thin chevrons separate them. Author labels in sentence case: type-label sets the caps. Ancestors are Link kind="nav" muted: on hover only their ink changes, to --role-link-hover (underlined where that ink is the text ink), and they share the Link's press and focus ring. A level with no href has no page and shows as plain text. renderLink builds each anchor, for example (href) => <NextLink href={href} />. Use a breadcrumb on pages two or more levels deep, never as a history trail.
Kinds
Inline, staircase and parent
inline (the default) is the in-page breadcrumb, and it reflows on its own width: below 768 px it is the parent link alone; from 768 px it is one line, collapsing the middle into a "…" menu past four levels; from 1024 px it shows up to six. It is an inline-size container, so give it a width in shrink-to-fit layouts. staircase is the section-bar form: below a 768 px viewport the toggle and truncated title open one indented row per level, and from there it is one line (four levels, six from 1024 px) whose crumbs truncate and whose current crumb, in bold, acts as the title. The section bar renders that line with withStaircase={false} and opens the staircase in its own panel. parent is always the parent link. Drag the frame's corner to watch the reflow.
inline
staircase
parent
import { Breadcrumb, type BreadcrumbCrumb } from '@fairgarden-private/design/components/Breadcrumb'
import styles from './kinds.module.css'
/** Six ancestors, one of them a level without a page. */
const path: BreadcrumbCrumb[] = [
{ label: 'Home', href: '#kinds' },
{ label: 'Programs', href: '#kinds' },
{ label: 'Conservation', href: '#kinds' },
{ label: 'Regional' },
{ label: 'Land trusts', href: '#kinds' },
{ label: 'Stewardship', href: '#kinds' },
]
export function BreadcrumbKinds() {
return (
<div className={styles.stack}>
<p className={styles.name}>inline</p>
<div className={styles.frame}>
<Breadcrumb items={path} current="Easement monitoring" />
</div>
<p className={styles.name}>staircase</p>
<Breadcrumb kind="staircase" items={path.slice(0, 3)} current="Easement monitoring" />
<p className={styles.name}>parent</p>
<Breadcrumb kind="parent" items={path} current="Easement monitoring" />
</div>
)
}
On grounds
On page grounds and fields
On a page ground the ancestors and chevrons are muted and the current page takes the text ink. On a deep field the crumbs take the dark scale's paper-colored ink, and where the muted role resolves to the text ink itself (some deep fields and every saturated one), weight and last position tell the current page apart.
paper
tide
forest
leaf
'use client'
import * as React from 'react'
import { Breadcrumb, type BreadcrumbCrumb } from '@fairgarden-private/design/components/Breadcrumb'
import { Ground } from '@fairgarden-private/design/components/Ground'
import {
isFieldPreset,
isPageGroundPreset,
presets,
type GroundPreset,
} from '@fairgarden-private/design/utils/scope'
import styles from './grounds.module.css'
const path: BreadcrumbCrumb[] = [
{ label: 'Home', href: '#grounds' },
{ label: 'Guides', href: '#grounds' },
]
/** The first preset that passes `test`, read from the preset table, never named here. */
function firstPreset(test: (preset: GroundPreset) => boolean): GroundPreset | undefined {
return (Object.keys(presets) as GroundPreset[]).find(test)
}
/** A sample surface: a field preset as an inset field, a page ground as a face. */
function Sample({
preset,
className,
children,
}: {
preset: GroundPreset
className: string
children: React.ReactNode
}) {
if (isFieldPreset(preset)) {
return (
<Ground kind="field" preset={preset} className={className}>
{children}
</Ground>
)
}
if (isPageGroundPreset(preset)) {
return (
<Ground kind="face" preset={preset} className={className}>
{children}
</Ground>
)
}
return null
}
/** A light page ground, a pastel, a deep field and a saturated field. */
const grounds = [
firstPreset((preset) => presets[preset].tone === 'light-base'),
firstPreset((preset) => presets[preset].tone === 'tinted'),
firstPreset((preset) => isFieldPreset(preset) && presets[preset].mode === 'always-dark'),
firstPreset((preset) => isFieldPreset(preset) && presets[preset].mode === 'always-light'),
].filter((preset): preset is GroundPreset => preset != null)
export function BreadcrumbGrounds() {
return (
<div className={styles.stack}>
{grounds.map((preset) => (
<Sample key={preset} preset={preset} className={styles.face}>
<p className={styles.name}>{preset}</p>
<Breadcrumb kind="staircase" items={path} current="Warblers of the Northeast" />
</Sample>
))}
</div>
)
}
In print the breadcrumb is replaced by one plain line of caps, ancestors joined by " / ", the current page omitted and no URLs. Pass printLine={false} where a page masthead prints the path instead.
API Reference
A nav named “Breadcrumb” holding the ancestors in order, then the
current page, unlinked and marked aria-current="page". Crumbs are
type-label caps; ancestors are --role-muted at --font-weight-4, the
current page --primary12 at --font-weight-6, and › chevrons separate
them. Crumbs never wrap: the middle collapses into a “…” menu instead.
Use it on pages two or more levels deep, never as a history trail.
| Prop | Type | Description |
|---|---|---|
current | | The current page’s title: last, unlinked, |
domainGlyph | | An optional solid domain glyph at |
items | | The ancestors, root first. The current page is |
kind | |
|
overflowLabel | | Accessible name and tooltip of the “…” overflow button. Default “More levels”. |
primary | | Primary Radix scale: every part’s ink and the focus ring. Never defaulted; omitted, it inherits the scope [D133]. |
printLine | | Prints the path as one plain line of caps, ancestors joined by “ / “,
current page omitted, no URLs (§7.8) [D80, D105]. Pass |
renderCrumb | | Builds the one line’s ancestor links in place of |
renderLink | | Builds each anchor, e.g. |
secondary | | Secondary Radix scale, accepted for the shared contract; the breadcrumb carries no accent. |
toggleLabel | | Accessible name of the staircase toggle. Default “Page path”. |
withStaircase | |
|
breadcrumb
BreadcrumbCrumb
BreadcrumbKind
BreadcrumbProps
breadcrumbStairRow
BreadcrumbVariants
Specification: DESIGN-SYSTEM.md §9.8 (breadcrumb), §5.10.2 (reflow) and §7.8 (print), with D80 and D165.