Accordion
Single or multiple, with optional collapsible mode when type="single".
Anatomy
import { Accordion } from "@spacing-ui/core";
<Accordion type="single" collapsible defaultValue="item-1">
<Accordion.Item value="item-1">
<Accordion.Trigger>Question 1</Accordion.Trigger>
<Accordion.Content>Answer 1</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-2">
<Accordion.Trigger>Question 2</Accordion.Trigger>
<Accordion.Content>Answer 2</Accordion.Content>
</Accordion.Item>
</Accordion>;API
Accordion (Root)
| Prop | Type | Description |
|---|---|---|
type | "single" | "multiple" | Required |
value / defaultValue | string (single) or string[] (multiple) | |
onValueChange | callback matching value type | |
collapsible | boolean (single only) | Allow closing the open item |
disabled | boolean |
Accessibility
- Trigger has
aria-expanded,aria-controls - Content has
role="region"andaria-labelledbypointing to its trigger - Keyboard: ArrowUp/Down, Home, End between triggers
Examples
Multiple open at once
<Accordion type="multiple" defaultValue={["a", "c"]}>
<Accordion.Item value="a">
<Accordion.Trigger>Section A</Accordion.Trigger>
<Accordion.Content>...</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="b">
<Accordion.Trigger>Section B</Accordion.Trigger>
<Accordion.Content>...</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="c">
<Accordion.Trigger>Section C</Accordion.Trigger>
<Accordion.Content>...</Accordion.Content>
</Accordion.Item>
</Accordion>Composing an FAQ list
Wrap Accordion.Item in your own component to standardize the trigger and content shape:
function Faq({ q, a, value }: { q: string; a: string; value: string }) {
return (
<Accordion.Item value={value}>
<Accordion.Trigger>{q}</Accordion.Trigger>
<Accordion.Content>{a}</Accordion.Content>
</Accordion.Item>
);
}Live demo
Testing
With @testing-library/react, target triggers by role and assert on aria-expanded:
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
test("expands the clicked item", async () => {
render(<MyAccordion />);
const trigger = screen.getByRole("button", { name: /section a/i });
await userEvent.click(trigger);
expect(trigger).toHaveAttribute("aria-expanded", "true");
});Last updated on