Accordion
A vertically stacked set of interactive headings that each reveal a section of content.
Installation
Install the following dependencies:
Set up the token layer and the StyleX compiler, if you have not already. See
Installation, and paste states.ts and state-styles.ts
from the same page. The trigger takes its focus ring and its disabled dim from
the first and reads Base UI's state through the second. The chevron reads the
trigger's hover and open state through the accordionTrigger marker in
markers.stylex.ts, also on that page. interop.css sizes any icon you put in
a trigger.
Copy and paste the following code into your project.
Update the import paths to match your project setup.
Usage
value and defaultValue are arrays, one entry per open item, even when only
one item can be open at a time.
Composition
AccordionTrigger renders the Base UI Header and Trigger together, and
AccordionContent renders the Panel around an inner element that holds the
padding.
Multiple
Use the multiple prop to keep more than one item open at a time.
Disabled
Use the disabled prop on AccordionItem to disable a single item, or on
Accordion to disable all of them.
Borders
Items draw a rule along their bottom edge, except the last. Add a frame through
xstyle on the Accordion and inline padding on each AccordionItem.
API reference
Pass render to replace a part's element or compose it with another component.
Every part wraps the Base UI Accordion part of the same name and accepts its
props. See the Base UI reference
for the full list. Each part also takes xstyle and className.
Accordion
| Prop | Type | Default |
|---|---|---|
value | string[] | — |
defaultValue | string[] | — |
onValueChange | (value: string[], details) => void | — |
multiple | boolean | false |
disabled | boolean | false |
keepMounted | boolean | false |
hiddenUntilFound | boolean | false |
hiddenUntilFound hides a closed panel with hidden="until-found" instead of
unmounting it, which lets the browser's find-in-page reach the text and open
the item. It overrides keepMounted.
AccordionItem
| Prop | Type | Default |
|---|---|---|
value | string | — |
disabled | boolean | — |
onOpenChange | (open: boolean, details) => void | — |
An item with no value gets a generated one. Set it when you control the
accordion or want an item open on first render.
AccordionTrigger
| Prop | Type | Default |
|---|---|---|
headerProps | Accordion.Header.Props | — |
style | CSSProperties | — |
The heading is the primitive's <h3>. Pass
headerProps={{ render: <h2 /> }} to fit the page's outline.
style is real inline CSS, merged over the compiled styles.
AccordionContent
xstyle and className apply to the inner element. style takes real inline
CSS on the panel. The panel animates its height between 0 and the measured
content height, and a padded box of height 0 still draws its padding.
Data attributes
| Attribute | On | Effect |
|---|---|---|
data-slot="accordion-content" | the panel | Targets the animated panel |
data-starting-style, data-ending-style | the panel | Base UI writes them while the panel animates |
data-open, data-disabled | item, panel | Base UI writes them |
data-panel-open, data-disabled | the trigger | Base UI writes them; the chevron flips |
data-slot="accordion-trigger-icon" | the chevron | Targets the chevron from a parent |
CSS variables
| Variable | On | Effect |
|---|---|---|
--accordion-panel-height | the panel | Base UI writes the measured height; the panel transitions to it |