Accordion

A vertically stacked set of interactive headings that each reveal a section of content.

Anatomy

Import and assemble the component:

1import { Accordion } from '@raystack/apsara'
2
3<Accordion>
4 <Accordion.Item>
5 <Accordion.Trigger />
6 <Accordion.Content />
7 </Accordion.Item>
8</Accordion>

Usage

Start with how many sections may be open at once, then decide whether you own that state.

Single vs multiple

single (the default) closes the open item when another opens. multiple lets any number stay open at once.

1<Accordion multiple={false}>
2 <Accordion.Item value="item-1">
3 <Accordion.Trigger>What is Apsara?</Accordion.Trigger>
4 <Accordion.Content>
5 Apsara is a modern design system and component library built with React
6 and TypeScript.
7 </Accordion.Content>
8 </Accordion.Item>
9 <Accordion.Item value="item-2">
10 <Accordion.Trigger>How do I get started?</Accordion.Trigger>
11 <Accordion.Content>
12 You can install Apsara using your preferred package manager and start
13 building your application.
14 </Accordion.Content>
15 </Accordion.Item>

Controlled

Pass value with onValueChange to own which item is open — needed when something outside the accordion has to open or close a section.

1(function ControlledAccordion() {
2 const [value, setValue] = React.useState("item-1");
3
4 return (
5 <Accordion value={value} onValueChange={setValue}>
6 <Accordion.Item value="item-1">
7 <Accordion.Trigger>Item 1</Accordion.Trigger>
8 <Accordion.Content>Content for item 1</Accordion.Content>
9 </Accordion.Item>
10 <Accordion.Item value="item-2">
11 <Accordion.Trigger>Item 2</Accordion.Trigger>
12 <Accordion.Content>Content for item 2</Accordion.Content>
13 </Accordion.Item>
14 </Accordion>
15 );

Disabled items

Individual accordion items can be disabled using the disabled prop.

1<Accordion>
2 <Accordion.Item value="item-1">
3 <Accordion.Trigger>Enabled Item</Accordion.Trigger>
4 <Accordion.Content>
5 This item is enabled and can be toggled.
6 </Accordion.Content>
7 </Accordion.Item>
8 <Accordion.Item value="item-2" disabled>
9 <Accordion.Trigger>Disabled Item</Accordion.Trigger>
10 <Accordion.Content>
11 This item is disabled and cannot be toggled.
12 </Accordion.Content>
13 </Accordion.Item>
14 <Accordion.Item value="item-3">
15 <Accordion.Trigger>Another Enabled Item</Accordion.Trigger>

Custom Content

The accordion content can contain any React elements, allowing for rich layouts and complex content.

1<Accordion>
2 <Accordion.Item value="item-1">
3 <Accordion.Trigger>Product Features</Accordion.Trigger>
4 <Accordion.Content>
5 <div style={{ padding: "16px" }}>
6 <h4>Key Features</h4>
7 <ul>
8 <li>Responsive design</li>
9 <li>Accessible components</li>
10 <li>TypeScript support</li>
11 <li>Customizable themes</li>
12 </ul>
13 </div>
14 </Accordion.Content>
15 </Accordion.Item>

API Reference

Items live in a root, and each pairs a trigger with a content panel.

Root

Groups all parts of the accordion.

Prop

Type

Item

Groups an accordion header with its content panel.

Prop

Type

Trigger

Toggles the visibility of its associated content.

Prop

Type

Content

Contains the collapsible content for an item.

Prop

Type

Slots

Every rendered part carries a stable data-slot attribute for styling and testing:

SlotElement
accordionThe root element that wraps all items
accordion-itemWrapper around a single header and its panel
accordion-headerThe header row that holds the trigger
accordion-triggerThe <button> that toggles the item
accordion-trigger-iconThe chevron icon inside the trigger
accordion-contentThe collapsible panel for an item
accordion-content-bodyThe padded <div> that holds the panel content

Accessibility

  • Follows the WAI-ARIA Accordion pattern
  • Trigger elements use aria-expanded to indicate open/closed state
  • Supports keyboard navigation with Enter and Space to toggle items
  • Content panels use aria-controls and aria-labelledby for association
  • Respects motion preferences: icon rotation and panel expand/collapse motion is enabled only when prefers-reduced-motion: no-preference