Skip to content
ArcadiaDesign
Read README.mdRead src/math.tsSearched for “export function”
export const clamp = (v: number, lo: number, hi: number) =>
  Math.min(hi, Math.max(lo, v));
12 pass so far

TSX

Thinking rows, tool lines, step groups, the work summary, notices and settings sections: every disclosure is this one. The header reads action, details, an optional end slot, then the chevron, which follows the text, appears on hover or focus and turns 90° when open; no space is held for it at rest. The panel is the kit's one fold, Unfold: it opens over 200ms and closes over 160ms on --ease-enter while its content fades, and the chevron turns with it.

Examples

A settings section

The same anatomy outside the stream: sm for UI text, an icon, and controls in the panel.

Nested

A work summary holding its steps. expandable={false} keeps the anatomy without a toggle, for a step with nothing to show.

Read README.md
Checked to-do list

Small

sm is UI text (13/18) for cards and trays; md, the default, is conversation text (15/24).

Read the codeAdd clamp and lerpRun the tests

Tone and state

rootStyle on the root takes where the disclosure sits and these knobs; its header and panel read them. Tones and sizes only reassign them, and hover reads its own (--collapsible-action-hover), so a colour you set never drops it. Set data-instant on any ancestor to still every transition inside it.

--collapsible-font
Ref<FontSize>Default var(--font-size-lg)
The header's font size.
--collapsible-lh
Ref<LineHeight>Default var(--line-height-lg)
The header's line height.
--collapsible-tracking
Ref<Tracking>Default var(--tracking-lg)
The header's letter spacing.
--collapsible-gap
Ref<Space> | Ref<"--stream-gap"> | "0px"Default var(--space-1)
Gap between the panel's children (and above the first).
--collapsible-end-gap
Ref<Space>Default var(--space-1)
Gap between the end slot's items.
--collapsible-icon
PaintDefault var(--icon-3)
The leading glyph.
--collapsible-action
PaintDefault var(--text-2)
The verb ("Explored").
--collapsible-action-hover
PaintDefault var(--text-1)
The verb under the pointer.
--collapsible-details
PaintDefault var(--text-3)
The object ("4 files, 2 searches").
--collapsible-details-hover
PaintDefault var(--text-2)
The object under the pointer.
--collapsible-ring-pad
Ref<Space> | "0px"Default var(--space-0-5)
How far the header and panel hang outside the text edge: room for the inset focus ring.
--collapsible-chevron-rest
0 | 1Default 0
Keep the disclosure chevron visible at rest (0 by default; use 1 for reference navigation).

Set --collapsible-chevron-rest to 1 when the disclosure should advertise itself before hover, as these reference sections do.

The header is a <button> with aria-expanded, controlling the panel. Closed panels stay in the DOM as hidden="until-found", so find in page reaches collapsed output and opens it. A loading header's shimmer is decorative; announce the work in a live region around the stream.

EnterSpace
Toggles the panel

Collapsible

open
boolean
Controlled open state.
defaultOpen
booleanDefault false
Initial open state when uncontrolled.
onOpenChange
(open: boolean, details: OpenChangeDetails) => void
Called when the header toggles it (details.reason: trigger-press) or a find-in-page match opens it.
disabled
booleanDefault false
Blocks toggling.
tone
"neutral" | "muted"Default "neutral"
muted: completed process rows (action and details at text-3; hover text-1 / text-2).
size
"sm" | "md"Default "md"
md: conversation text, 15/24. sm: UI text, 13/18, for cards and trays.
expandable
booleanDefault true
false: a static line (no chevron, no toggle), same anatomy.
loading
booleanDefault false
Live: the action shimmers (Shimmer secondary, tertiary when muted).
instant
boolean
Skip every height/opacity/rotation transition (hydration, bulk collapse, live → ended).
rootStyle
RootStyle<CollapsibleKnobs>
Typed StyleX override: where the disclosure sits and its --collapsible-* knobs.
className
string
A product's hook class for its own rules (being retired, counted by ui.lint's kit-classname).

Rest props go to <div> props.

actionrequired
ReactNode
The verb: "Explored", "Thought", "Worked for". Pass a node for custom content.
details
ReactNode
The object: "4 files, 2 searches", "12s", a path. Gives way first: its end fades.
icon
IconName | ReactElement
Optional leading glyph (icon-3). The glass transcript mostly has none.
end
ReactNode
Trailing inline content before the chevron, e.g. diff stats "+10 −1".
tone
"neutral" | "muted"
Overrides the root's tone for this header only.
loading
boolean
Overrides the root's loading state for this header only.
title
string
The header's hover hint. Shown as the kit Tooltip beside the row, never the native title attribute: a browser tooltip opens under the pointer and lands on the next line, which in a transcript covers the row below.
render
RenderProp<{ disabled: boolean }>
Replace the rendered element, e.g. render={<a href="/settings" />}, or a function of props and state.
disabled
boolean
Native disabled: no pointer events, no tooltip, skipped by Tab.
focusableWhenDisabled
boolean
Keep a disabled control focusable and hoverable (aria-disabled), so a tooltip can say why.
nativeButton
boolean
Button semantics, inferred from what renders: a <button> is native, an <a> stays a link, anything else gets role="button" and key handling. false forces button semantics on whatever renders (a link acting as a button).
className
string
A product's hook class for its own rules (being retired, counted by ui.lint's kit-classname).

Rest props go to <button> props.

hiddenUntilFound
booleanDefault true
Closed panels stay in the DOM as hidden="until-found", so ⌘F finds collapsed output (and opens it). false: the content unmounts once the fold has closed.
bare
booleanDefault false
Open, no header yet: no gap above, no clip. It only closes at once.
className
string
A product's hook class for its own rules (being retired, counted by ui.lint's kit-classname).

Rest props go to <div> props.