Accordion
Show and hide related sections of content.
Accordion groups related sections behind expandable headings. Prefer stable item IDs when sections may be reordered.
Import
import { Accordion, type AccordionValue } from "@puzzle-ui/ui";Basic usage
Each item has a title and content. When using defaultValue or value, every item must also have a unique id.
The Support item demonstrates disabled: its trigger cannot be activated.
Multiple sections
type="multiple" is the default. Pass an array of IDs to open more than one section. In multiple mode, onValueChange returns an array; in single mode it returns an ID or null when the last section closes.
Keep one section open
In single mode, collapsible={false} prevents the currently open section from being closed by its trigger. Set an initial value if a section should be open from the start.
Controlled selection
Pair value with onValueChange. Stable IDs keep open sections associated with the same items after reordering. Do not mix the ID-based and index-based selection APIs.
Panel lifecycle and semantics
headingLevel matches the surrounding document hierarchy. region explicitly enables or disables panel landmarks. With unMountOnClose, content unmounts after the closing animation; reopening resets local state. Enter a note and close/reopen the section to try it.
API
Accordion
AccordionItemId is string | number. AccordionValue is an ID, a readonly array of IDs, or null.
| Prop | Type | Default | Description |
|---|---|---|---|
items | AccordionItemData[] | Required | Sections to render. |
type | "single" | "multiple" | "multiple" | Whether more than one section can open. |
value | AccordionValue | - | Controlled open IDs; requires unique IDs on every item. |
defaultValue | AccordionValue | - | Initial uncontrolled open IDs. |
onValueChange | (value: AccordionItemId | AccordionItemId[] | null) => void | - | Next open ID(s). |
collapsible | boolean | true | Allows the open item to collapse in single mode. |
initialOpenItemIndexes | number[] | [] | Initial uncontrolled open indexes (compatibility API). |
openItemIndexes | number[] | - | Controlled open indexes (compatibility API). |
onChange | (indexes: number[]) => void | - | Next open indexes, also called in ID mode. |
headingLevel | 1 | 2 | 3 | 4 | 5 | 6 | 3 | Semantic heading level for triggers. |
region | boolean | items.length <= 6 | Adds region landmarks to panels. |
unMountOnClose | boolean | false | Unmounts content after its closing animation. |
className | string | - | Additional class on the root div. |
triggerClassName | string | - | Additional class on each trigger. |
panelClassName | string | - | Additional class on each animated panel. |
contentClassName | string | - | Additional class on each content wrapper. |
Other native div attributes are forwarded to the root, except children and onChange.
AccordionItemData
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | number | - | Stable identifier; required for ID-based selection. |
title | ReactNode | Required | Trigger content. |
content | ReactNode | Required | Expandable panel content. |
disabled | boolean | false | Prevents user toggling. |
Accessibility
Triggers are native buttons inside headings, with aria-expanded and aria-controls. Use Tab to move between enabled triggers and Enter or Space to toggle them. Keep headings concise and use the panel for longer content.