A React accordion with collapsible Liquid Glass panels and keyboard support.
Accordion renders a stack of disclosure panels on one glass surface. Each entry is a real heading and button, and the panel height animates when it opens.
Each entry in items renders a real heading and button. The default plus indicator rotates into a close icon, and the panel animates its height.
The default mode keeps a single panel open. Add multiple to let several panels stay expanded at once:
Supports xs / sm / md / lg / xl, defaulting to md. Trigger height, padding, typography, and the indicator scale together.
value and onValueChange make the open panels fully controlled. The example below can open or collapse every panel from one button:
Set disabled on the root to disable every trigger, or on a single item to disable only that panel.
Closed panels are removed from the DOM by default. Set keepMounted to keep them mounted so form state survives, or hiddenUntilFound to keep them searchable with the browser's find-in-page.
Each entry renders a native button inside a real heading (an <h3> by default). The trigger exposes aria-expanded; while its panel is open, it also exposes aria-controls. The panel is labelled by its trigger. Enter or Space toggles the focused panel. Disabled triggers stay in the document but are skipped by the Tab key.
Keep the heading text meaningful; the visual style is not a substitute for a real document outline. See the accessibility guide for shared interaction patterns.
Accordion
| Prop | Type | Default | Description |
|---|---|---|---|
value | Value[] | — | Controlled expanded item values. |
defaultValue | Value[] | [] | Initially expanded item values. |
onValueChange | (value: Value[], details) => void | — | Called when the expanded values change. |
multiple | boolean | false | Allows more than one panel to stay open. |
disabled | boolean | false | Disables every trigger. |
hiddenUntilFound | boolean | false | Keeps closed panels searchable with hidden="until-found". |
keepMounted | boolean | false | Keeps closed panels mounted in the DOM. |
loopFocus | boolean | — | Deprecated. No longer affects keyboard focus. |
orientation | "horizontal" | "vertical" | "vertical" | Deprecated. No longer affects keyboard focus. |
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Controls trigger height, padding, text, and the indicator. |
items | readonly AccordionItemProps[] | — | Panels rendered inside the accordion. |
render | ReactElement | ((props, state) => ReactElement) | — | Replaces the root element. |
ref | Ref<HTMLDivElement> | — | Ref forwarded to the root element. |
className | string | — | Tailwind classes merged into the root. |
style | CSSProperties | — | Inline styles merged into the same element as className. |
ui | { root?: ClassValue; glass?: ClassValue; overlay?: ClassValue; content?: ClassValue; item?: ClassValue; header?: ClassValue; trigger?: ClassValue; title?: ClassValue; indicator?: ClassValue; indicatorIcon?: ClassValue; panel?: ClassValue; panelContent?: ClassValue } | — | Tailwind classes for internal slots, keyed by data-slot. |
AccordionItemProps
| Prop | Type | Default | Description |
|---|---|---|---|
value | any | — | Required identifier used by the accordion value. |
title | ReactNode | — | Required visible heading inside the trigger. |
content | ReactNode | — | Panel content. |
indicator | ReactNode | false | Built-in plus icon | Replaces the default indicator. Set to false to hide it. |
disabled | boolean | false | Disables this item. |
onOpenChange | (open: boolean, details) => void | — | Called when this panel opens or closes. |
render | ReactElement | ((props, state) => ReactElement) | — | Replaces the item root element. |
ref | Ref<HTMLDivElement> | — | Ref forwarded to the item root. |
className | string | — | Tailwind classes merged into the item root. |
style | CSSProperties | — | Inline styles merged into the same element as className. |
ui | { item?: ClassValue; header?: ClassValue; trigger?: ClassValue; title?: ClassValue; indicator?: ClassValue; indicatorIcon?: ClassValue; panel?: ClassValue; panelContent?: ClassValue } | — | Tailwind classes for this item's internal slots, keyed by data-slot. |
Root ui is merged into every item first, then the item's ui, then the item's className.
| Attribute | Description |
|---|---|
data-disabled | Present when the accordion or an item is disabled. |
data-orientation | Indicates the orientation (horizontal or vertical). |
data-index | Indicates the item index on item and trigger elements. |
data-open | Present when an item is open. |
data-panel-open | Present on a trigger while its panel is open. |
data-starting-style | Present when a panel begins animating in. |
data-ending-style | Present when a panel is animating out. |
data-slot | Marks internal parts (root, glass, overlay, content, item, header, trigger, title, indicator, indicator-icon, panel, panel-content). |
The component uses the shared glass material. Tune shared --ui-glass-* tokens on a parent, use className for layout, and use ui for internal slots keyed by data-slot. Component-specific values live in src/theme/accordion.ts. See the theming guide for token layers and presets.