A stack of headings that each show and hide a panel, one or several at a time.
Example
import { Accordion, AccordionItem } from "@elements/ui/accordion";
<Accordion value={["shipping"]} collapsible>
<AccordionItem value="shipping" title="What are your shipping options?">
Standard shipping takes 5 to 7 business days. Express arrives in 2.
</AccordionItem>
<AccordionItem value="returns" title="What is your return policy?">
Return anything within 30 days for a full refund.
</AccordionItem>
</Accordion>
Parts
| Part |
What it is |
Accordion |
The root. Owns value, the list of open items. |
AccordionItem |
One section: a heading with a trigger button, and its panel. |
.accordion-trigger |
The button in each header. Its label is .accordion-trigger-label. |
.accordion-content |
The panel region; .accordion-content-inner holds the padding. |
.accordion-chevron |
The chevron; turns with the item's state. |
Attributes
Accordion
| Attribute |
Type |
Default |
Description |
value |
string[] (two-way) |
[] |
Values of the open items. Give a starting value or bind it to control it. |
multiple |
boolean |
false |
Several items may be open at once. |
collapsible |
boolean |
false |
With one open at a time, the open item can be closed too. Multiple mode always can. |
disabled |
boolean |
false |
Disables every item. |
orientation |
"vertical" | "horizontal" |
"vertical" |
Which arrow keys move between triggers. |
dir |
"" | "ltr" | "rtl" |
"" |
Reading direction. Empty inherits. Flips Left and Right when horizontal. |
loop |
boolean |
true |
Arrow keys wrap from the last trigger to the first. |
hiddenUntilFound |
boolean |
false |
Closed panels stay searchable: find in page, or a link to their text, opens the item. |
variant |
"default" | "bordered" |
"default" |
bordered frames the items in a surface. |
onValueChange |
(value: string[], details: DisclosureDetails) => void |
() => {} |
Called when a trigger changes the open items, before the change, with details second (reason, event, trigger, cancel(), isCanceled; reason trigger-press). details.cancel() keeps the items as they were. Not called for changes the caller makes. |
class |
string |
"" |
Extra classes on the root. |
AccordionItem
| Attribute |
Type |
Default |
Description |
value |
string |
"" |
Identifies the item in the root's value. Omitted, the item gets a generated value. |
title |
string |
"" |
The trigger label. |
disabled |
boolean |
false |
The item cannot be opened or closed and arrows skip it. |
level |
2 | 3 | 4 | 5 | 6 |
3 |
Heading level of the header, to fit the page's outline. |
hiddenUntilFound |
boolean |
false |
This item's closed panel stays searchable (the root's hiddenUntilFound sets it for every item). |
class |
string |
"" |
Extra classes on the item. |
onOpenChange |
(open: boolean, details: DisclosureDetails) => void |
() => {} |
Called when a trigger opens or closes this item, including when opening another closes it, with the root's details. |
Slots
| Slot |
Part |
Content |
default |
Accordion |
AccordionItems. |
default |
AccordionItem |
The panel content. |
trigger |
AccordionItem |
Rich trigger content (an icon, a badge), placed after title. |
Keyboard
| Keys |
Action |
Space / Enter |
Opens or closes the focused section. |
Tab / Shift + Tab |
Moves to the next or previous focusable element; every trigger is a tab stop. |
ArrowDown / ArrowUp |
Next or previous trigger (vertical). |
ArrowRight / ArrowLeft |
Next or previous trigger (horizontal; flipped right to left). |
Home / End |
First or last trigger. |
Data attributes
| Attribute |
Values |
On |
Description |
data-orientation |
"vertical" | "horizontal" |
root, item, header, trigger, content |
|
data-state |
"open" | "closed" |
item, header, trigger, content |
|
data-disabled |
present when disabled |
item, header, trigger, content |
|
data-open |
present while open |
item, header, content |
|
data-panel-open |
present while its panel is open |
trigger |
|
data-animating |
present while the height animates |
content |
|
data-starting-style / data-ending-style |
the first frames of an open / the whole close |
content |
|
data-index |
the item's position, from 0 |
item, header, trigger, content |
|
--content-height |
px |
content |
Measured height, for custom keyframes |
--content-width |
px |
content |
|
Accessibility
- Follows the WAI-ARIA accordion pattern: each header is role="heading" with aria-level, holding a native button with aria-expanded and aria-controls.
- Each panel is role="region" labelled by its trigger.
- When the open item cannot be closed (one at a time, not collapsible), its trigger gets aria-disabled="true".
- Closed panels are hidden, so their controls leave the tab order. The server renders the open items open, so nothing moves on load.
See also