Accordion
A Base UI Accordion for long reference content scanned by heading: ruled rows, each a heading that opens its panel in place.
import { Accordion, AccordionItem } from '@fairgarden-private/design/components/Accordion'
The glyph is LTA's disclosure glyph: two thin arrows that point outward while collapsed and inward while expanded, muted then in the text ink. It swaps direction and never rotates; chevrons are kept for popups. Several items may be open at once. Panels open with a clip reveal, instantly under reduced motion, and stay in the DOM so find-in-page reaches them and print shows every panel expanded. Never hide content a task depends on, and never convert an accordion into tabs.
Glyphs and the strong top
Glyphs and the strong top
glyph="disclosure" is the default. headed draws a --border-size-2 rule above the first item when the accordion follows a heading. glyph="plusminus" is the documented alternate for product UI; never mix the two on one page. A disabled item mutes its title and glyph, but prefer removing it.
Open dawn to dusk every day. Boardwalks close after heavy frost.
Twelve spaces at the north lot; the 42 bus stops at the gate.
Unavailable while the page is updated.
Trail notes
Flat and accessible, with benches every quarter mile.
Steep switchbacks; muddy in spring.
The plus/minus circle is the alternate for product UI.
Never mix it with the disclosure glyph on one page.
import { Accordion, AccordionItem } from '@fairgarden-private/design/components/Accordion'
import styles from './variants.module.css'
/**
* The ruled accordion with the LTA disclosure glyph (default), the strong
* top rule for an accordion that follows a heading, and the plus/minus
* alternate.
*/
export function AccordionVariants() {
return (
<div className={styles.stack}>
<Accordion defaultValue={['hours']}>
<AccordionItem value="hours" title="Hours and seasons">
<p className={styles.copy}>Open dawn to dusk every day. Boardwalks close after heavy frost.</p>
</AccordionItem>
<AccordionItem value="parking" title="Parking and transit">
<p className={styles.copy}>Twelve spaces at the north lot; the 42 bus stops at the gate.</p>
</AccordionItem>
<AccordionItem value="rules" title="Preserve rules" disabled>
<p className={styles.copy}>Unavailable while the page is updated.</p>
</AccordionItem>
</Accordion>
<section className={styles.section}>
<h3 className={styles.heading}>Trail notes</h3>
<Accordion headed>
<AccordionItem value="loop" title="Meadow loop, 1.2 miles">
<p className={styles.copy}>Flat and accessible, with benches every quarter mile.</p>
</AccordionItem>
<AccordionItem value="ridge" title="Ridge trail, 3.4 miles">
<p className={styles.copy}>Steep switchbacks; muddy in spring.</p>
</AccordionItem>
</Accordion>
</section>
<Accordion glyph="plusminus">
<AccordionItem value="account" title="Account settings">
<p className={styles.copy}>The plus/minus circle is the alternate for product UI.</p>
</AccordionItem>
<AccordionItem value="notifications" title="Notifications">
<p className={styles.copy}>Never mix it with the disclosure glyph on one page.</p>
</AccordionItem>
</Accordion>
</div>
)
}
Primary scale
Primary scale
primary drives every part. The expanded glyph is the text ink, not an accent, so secondary is unused.
Rules, titles, glyph and panel text re-resolve together.
The collapsed glyph is the muted step of the same scale.
The strong top rule is the text step of the scale.
import { Accordion, AccordionItem } from '@fairgarden-private/design/components/Accordion'
import styles from './color.module.css'
/** `primary` drives every part: rules, titles, glyph and panel text. `secondary` is unused. */
export function AccordionColor() {
return (
<div className={styles.stack}>
<Accordion primary="plum" defaultValue={['a']}>
<AccordionItem value="a" title="Primary plum">
<p className={styles.copy}>Rules, titles, glyph and panel text re-resolve together.</p>
</AccordionItem>
<AccordionItem value="b" title="Collapsed glyph">
<p className={styles.copy}>The collapsed glyph is the muted step of the same scale.</p>
</AccordionItem>
</Accordion>
<Accordion primary="slate" headed>
<AccordionItem value="a" title="Primary slate, headed">
<p className={styles.copy}>The strong top rule is the text step of the scale.</p>
</AccordionItem>
</Accordion>
</div>
)
}
On grounds
On paper and forest
paper
Arrows point inward.
Arrows point outward.
forest
Arrows point inward.
Arrows point outward.
import { Accordion, AccordionItem } from '@fairgarden-private/design/components/Accordion'
import { PresetGround } from '@/components/PresetGround'
import styles from './grounds.module.css'
const presets = ['paper', 'forest'] as const
/** Pure type and line: on forest the collapsed glyph is already the one ink, so direction carries the state. */
export function AccordionGrounds() {
return (
<div className={styles.row}>
{presets.map((preset) => (
<PresetGround key={preset} preset={preset} className={styles.face}>
<p className={styles.name}>{preset}</p>
<Accordion defaultValue={['open']}>
<AccordionItem value="open" title="Expanded">
<p className={styles.copy}>Arrows point inward.</p>
</AccordionItem>
<AccordionItem value="closed" title="Collapsed">
<p className={styles.copy}>Arrows point outward.</p>
</AccordionItem>
</Accordion>
</PresetGround>
))}
</div>
)
}
API Reference
Accordion
A set of disclosure rows divided by --role-rule rules, including after
the last item. Several items may be open at once (multiple, default
true). Closed panels stay in the DOM (hiddenUntilFound, default
true), so find-in-page reaches them and every panel prints expanded.
Never convert an accordion into tabs.
| Prop | Type | Description |
|---|---|---|
glyph | |
|
headed | | Draws a |
primary | | Primary Radix scale: rules, titles, glyph and panel text. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale, accepted for the shared contract; no part uses it. |
AccordionItem
One row: a heading wrapping the trigger (optional icon, title, glyph at the row’s end, top-aligned to the title’s first line) and the panel. The whole row is the target. There is no fill change when it opens.
| Prop | Type | Description |
|---|---|---|
headingLevel | | The heading level wrapping the trigger. Default |
icon | | An optional leading subject symbol (§6.10), Material Symbols Rounded at the tag tier; the panel indents to the title column. Dropped below 360 px so the title keeps its width. |
panelProps | | Props for the panel, such as |
title | | The row’s title, |
Additional types
AccordionGlyph
type AccordionGlyph = 'disclosure' | 'plusminus'<'disclosure' | 'plusminus' | null | undefined>AccordionItemProps
Props for AccordionItem: Base UI Accordion Item props (without title) plus the row content.
type AccordionItemProps = {
/**
* The row's title, `type-subhead` in `--primary12`. Write it to stand
* alone: it becomes the printed heading.
*/
title: React.ReactNode;
/**
* An optional leading subject symbol (§6.10), Material Symbols Rounded at
* the tag tier; the panel indents to the title column. Dropped below
* 360 px so the title keeps its width.
*/
icon?:
| 'menu'
| 'search'
| 'circle'
| 'arrow_forward'
| 'arrow_upward'
| 'expand_more'
| 'close'
| 'remove'
| 'add'
| 'check'
| 'chevron_right'
| 'chevron_left'
| 'more_horiz'
| 'play_arrow'
| 'pause'
| 'download'
| 'zoom_in'
| 'zoom_out'
| 'recenter'
| 'help'
| 'mail';
/** The heading level wrapping the trigger. Default `3`. */
headingLevel?: HeadingLevel;
/** Props for the panel, such as `keepMounted`. */
panelProps?: Omit<AccordionPanelProps, 'children'>;
}AccordionProps
Props for Accordion: Base UI Accordion Root props plus the glyph, headed and color axes.
type AccordionProps<Value = unknown> = AccordionRoot.Props<Value> & {
glyph?: 'disclosure' | 'plusminus' | null;
headed?: boolean | null;
primary?:
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'ruby'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
secondary?:
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'ruby'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
}Specification: DESIGN-SYSTEM.md §10.13 (accordion and collapsible).