Accordion
A set of headed sections that expand and collapse.
import { Accordion } from "@evolve-storefront/ui/accordion";Design notes
react-aria-components owns the behaviour, which is the whole reason this is a
primitive rather than markup: a trigger that is a real <button> inside a
heading, aria-expanded on it, and aria-controls pointing at the panel.
A collapsed panel is hidden="until-found", not unmounted — out of the
accessibility tree, but still reachable by the browser's find-in-page, which
expands the section it lands in. For an FAQ that is the behaviour you want.
Triggers are reached with Tab, which is the disclosure pattern. Arrow-key movement between them is the accordion pattern's optional extra and RAC does not implement it, so neither do we.
Single-open by default — pass allowsMultipleExpanded for a set where more than
one answer is useful at a time. Collapsible either way.
Preview
Usage
Single-open: opening a second section closes the first.
<Accordion> {sections.map((section) => ( <AccordionItem key={section.id} id={section.id}> <AccordionTrigger headingLevel={3}>{section.question}</AccordionTrigger> <AccordionPanel>{section.answer}</AccordionPanel> </AccordionItem> ))}</Accordion>Props
| Prop | Type | Description |
|---|---|---|
allowsMultipleExpanded? | boolean | Let more than one section stand open. Default: one at a time. |
defaultExpandedKeys? | Iterable<string> | Ids of the sections open on first render. |
expandedKeys? | Iterable<string> | The open sections, for a caller that owns the state. |
onExpandedChange? | ((keys: Set<string>) => void) | Reports the open set. Pairs with |
Any other props go to the root element, like on a plain HTML element.
Change the layout
Pass children to Accordion to arrange its parts yourself. Every part is exported from @evolve-storefront/ui/accordion.
<Accordion> {sections.map((section) => ( <AccordionItem key={section.id} id={section.id}> <AccordionTrigger headingLevel={3}>{section.question}</AccordionTrigger> <AccordionPanel>{section.answer}</AccordionPanel> </AccordionItem> ))}</Accordion>AccordionItemOne section: an AccordionTrigger and an AccordionPanel.
| Prop | Type | Description |
|---|---|---|
id | string | Identifies the section in |
Any other props go to the root element, like on a plain HTML element.
AccordionPanelThe section's content.
No props of its own.
AccordionTriggerThe control that opens a section.
| Prop | Type | Description |
|---|---|---|
headingLevel? | HeadingLevel | The level of the heading wrapping the trigger. MoreA heading, not a bare button, because that is what puts the sections in a screen reader's heading list. RAC defaults it to 3, which is right only at one depth — so a caller that knows its depth passes one. |
Any other props go to the root element, like on a plain HTML element.

