Collapsible
A Base UI Collapsible for one in-place disclosure, such as "Show 12 more" under a truncated list, led by the LTA disclosure glyph.
import {
Collapsible,
CollapsiblePanel,
CollapsibleTrigger,
} from '@fairgarden-private/design/components/Collapsible'
The trigger is the disclosure glyph at the 16 px tier plus a label, and the whole trigger is the target. openLabel swaps the label while the panel is open ("Show less"). The panel opens with a clip reveal, instantly under reduced motion, and stays in the DOM, so it prints expanded while the trigger is hidden. DisclosureGlyph is exported for any other in-place disclosure; it reads its state from the Base UI trigger around it.
Show more
Show more
The arrows point outward while collapsed and inward while open, muted then in the text ink; they never rotate. A disabled trigger mutes label and glyph.
- Bluestem Prairie
- Heron Marsh
- Oak Hollow
- Cedar Bluff
- Fox Run
- Willow Bend
- Kettle Pond
- Sandhill Flats
No subdivision, no new structures, and no removal of native trees.
Not shown.
import {
Collapsible,
CollapsiblePanel,
CollapsibleTrigger,
} from '@fairgarden-private/design/components/Collapsible'
import styles from './variants.module.css'
const preserves = ['Bluestem Prairie', 'Heron Marsh', 'Oak Hollow', 'Cedar Bluff']
const more = ['Fox Run', 'Willow Bend', 'Kettle Pond', 'Sandhill Flats']
/** "Show more" with a swapped open label, and a disabled trigger. */
export function CollapsibleVariants() {
return (
<div className={styles.stack}>
<Collapsible>
<ul className={styles.list}>
{preserves.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
<CollapsiblePanel>
<ul className={styles.list}>
{more.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
</CollapsiblePanel>
<CollapsibleTrigger openLabel="Show less">Show {more.length} more</CollapsibleTrigger>
</Collapsible>
<Collapsible defaultOpen>
<CollapsibleTrigger>Deed restrictions</CollapsibleTrigger>
<CollapsiblePanel>
<p className={styles.copy}>No subdivision, no new structures, and no removal of native trees.</p>
</CollapsiblePanel>
</Collapsible>
<Collapsible disabled>
<CollapsibleTrigger>Survey records (unavailable)</CollapsibleTrigger>
<CollapsiblePanel>
<p className={styles.copy}>Not shown.</p>
</CollapsiblePanel>
</Collapsible>
</div>
)
}
Primary scale
Primary scale
Primary plum.
Primary bronze, open.
import {
Collapsible,
CollapsiblePanel,
CollapsibleTrigger,
} from '@fairgarden-private/design/components/Collapsible'
import styles from './color.module.css'
/** `primary` drives the label, glyph and panel text. */
export function CollapsibleColor() {
return (
<div className={styles.row}>
<Collapsible primary="plum">
<CollapsibleTrigger openLabel="Hide details">Show details</CollapsibleTrigger>
<CollapsiblePanel>
<p className={styles.copy}>Primary plum.</p>
</CollapsiblePanel>
</Collapsible>
<Collapsible primary="bronze" defaultOpen>
<CollapsibleTrigger openLabel="Hide details">Show details</CollapsibleTrigger>
<CollapsiblePanel>
<p className={styles.copy}>Primary bronze, open.</p>
</CollapsiblePanel>
</Collapsible>
</div>
)
}
On grounds
On paper and forest
paper
Fox Run, Willow Bend, Kettle Pond.
forest
Fox Run, Willow Bend, Kettle Pond.
import {
Collapsible,
CollapsiblePanel,
CollapsibleTrigger,
} from '@fairgarden-private/design/components/Collapsible'
import { PresetGround } from '@/components/PresetGround'
import styles from './grounds.module.css'
const presets = ['paper', 'forest'] as const
/** The glyph steps from muted to the text ink on paper; on forest both states are the one ink. */
export function CollapsibleGrounds() {
return (
<div className={styles.row}>
{presets.map((preset) => (
<PresetGround key={preset} preset={preset} className={styles.face}>
<p className={styles.name}>{preset}</p>
<Collapsible>
<CollapsibleTrigger openLabel="Show less">Show 3 more</CollapsibleTrigger>
<CollapsiblePanel>
<p className={styles.copy}>Fox Run, Willow Bend, Kettle Pond.</p>
</CollapsiblePanel>
</Collapsible>
</PresetGround>
))}
</div>
)
}
API Reference
Collapsible
One in-place disclosure (§10.13): a CollapsibleTrigger (the disclosure
glyph at the inline tier plus a label) and a CollapsiblePanel. Use it for
“Show more” on truncated lists and optional detail; never hide content a
task depends on. Every panel prints expanded and the trigger is hidden.
| Prop | Type | Description |
|---|---|---|
primary | | Primary Radix scale: label, 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. |
CollapsibleTrigger and CollapsiblePanel
The trigger: the disclosure glyph (16 px, chrome tier) then the label,
e.g. “Show 12 more”. The whole trigger is the ≥ 44 px target; the glyph
alone never is.
| Prop | Type | Description |
|---|---|---|
openLabel | | The label while the panel is open, e.g. “Show less”. Omitted, the children stay. Author it in sentence case. |
The panel. It stays in the DOM while closed (hiddenUntilFound, default
true), so find-in-page reaches it and print shows it expanded. It opens
with a clip reveal at --ds-duration-disclosure, instant under reduced
motion.
DisclosureGlyph
LTA’s expand/collapse glyph [D109]: two thin arrows pointing outward from
a short center hairline when collapsed, inward when expanded (§6.10). It
reads the state from the nearest Base UI trigger’s data-panel-open, so
place it inside an Accordion or Collapsible trigger. The direction swaps
instantly and never rotates; collapsed it is --role-muted, expanded
--primary12. Decorative: the trigger carries the state (aria-expanded).
| Prop | Type | Description |
|---|---|---|
size | |
|
Additional types
collapsible
type collapsible = collapsibleCollapsiblePanelProps
Props for CollapsiblePanel: Base UI Collapsible Panel props.
type CollapsiblePanelProps = CollapsiblePanel.CollapsiblePanelPropsCollapsibleProps
Props for Collapsible: Base UI Collapsible Root props plus the color axes.
type CollapsibleProps = CollapsibleRootProps & {
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
}CollapsibleTriggerProps
Props for CollapsibleTrigger: Base UI Collapsible Trigger props plus the open label.
type CollapsibleTriggerProps = CollapsibleTriggerProps & { openLabel?: React.ReactNode }disclosureGlyph
The disclosure glyph’s two tiers (§10.13).
type disclosureGlyph = disclosureGlyphdisclosureGlyphHost
Add to an icon-only control whose only content is the disclosure glyph (the staircase or section-bar toggle): hover and press then swap the glyph to the next tier’s weight (§10.1 icon states) [D181]. Trigger rows (Accordion, FAQ, Collapsible) never take it: their glyph does not change on hover [D109].
type disclosureGlyphHost = stringDisclosureGlyphProps
Props for DisclosureGlyph: SVG props (without children) and the tier.
type DisclosureGlyphProps = {
/**
* `row` (default): `--size-px-4` (20 px) at `--ds-stroke-1-5`, for trigger
* rows (Accordion, FAQ). `chrome`: `--size-px-3` (16 px) at
* `--ds-stroke-1-25`, for bars, drawer groups and an inline "Show more".
*/
size?: 'row' | 'chrome' | null;
}Specification: DESIGN-SYSTEM.md §10.13 (accordion and collapsible) and §6.10 (the disclosure glyph).