# Accordion

URL: https://ark-ui.com/docs/components/accordion
Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/accordion.mdx

A collapsible component for displaying content in a vertical stack.

---

<ComponentPreview id="Accordion" />

## Anatomy

<Anatomy id="accordion" />

```tsx
<Accordion.Root>
  <Accordion.Item>
    <Accordion.ItemTrigger>
      <Accordion.ItemIndicator />
    </Accordion.ItemTrigger>
    <Accordion.ItemContent />
  </Accordion.Item>
</Accordion.Root>
```

## Examples

### Default Value

Set the `defaultValue` prop to specify which item should be expanded by default.

**Example: basic**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import { ChevronDown } from 'lucide-ripple';
import styles from 'styles/accordion.module.css';

export component Basic() {
  <Accordion.Root class={styles.Root} defaultValue={['ark-ui']}>
    for (const item of items; key item.value) {
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>
          {item.title}
          <Accordion.ItemIndicator class={styles.ItemIndicator}>
            <ChevronDown />
          </Accordion.ItemIndicator>
        </Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    }
  </Accordion.Root>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

### Controlled

Use the `value` and `onValueChange` props to control the expanded items.

**Example: controlled**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import { track } from 'ripple';
import { ChevronDown } from 'lucide-ripple';
import styles from 'styles/accordion.module.css';

export component Controlled() {
  let value = track<string[]>([]);

  <Accordion.Root
    class={styles.Root}
    {value}
    onValueChange={(details) => {
      @value = details.value;
    }}
  >
    for (const item of items; key item.value) {
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>
          {item.title}
          <Accordion.ItemIndicator class={styles.ItemIndicator}>
            <ChevronDown />
          </Accordion.ItemIndicator>
        </Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    }
  </Accordion.Root>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

### Root Provider

An alternative way to control the accordion is to use the `RootProvider` component and the `useAccordion` hook. This way
you can access the state and methods from outside the component.

**Example: root-provider**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import { useAccordion } from 'ark-ripple/accordion';
import { ChevronDown } from 'lucide-ripple';
import styles from 'styles/accordion.module.css';

export component RootProvider() {
  const accordion = useAccordion({ multiple: true, defaultValue: ['ark-ui'] });

  <div class="stack">
    <output>
      {'Value: '}
      {JSON.stringify(@accordion.value)}
    </output>

    <Accordion.RootProvider class={styles.Root} value={accordion}>
      for (const item of items; key item.value) {
        <Accordion.Item class={styles.Item} value={item.value}>
          <Accordion.ItemTrigger class={styles.ItemTrigger}>
            {item.title}
            <Accordion.ItemIndicator class={styles.ItemIndicator}>
              <ChevronDown />
            </Accordion.ItemIndicator>
          </Accordion.ItemTrigger>
          <Accordion.ItemContent class={styles.ItemContent}>
            <div class={styles.ItemBody}>{item.content}</div>
          </Accordion.ItemContent>
        </Accordion.Item>
      }
    </Accordion.RootProvider>
  </div>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

### Collapsible

Use the `collapsible` prop to allow the user to collapse all panels.

**Example: collapsible**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import { ChevronDown } from 'lucide-ripple';
import styles from 'styles/accordion.module.css';

export component Collapsible() {
  <Accordion.Root class={styles.Root} defaultValue={['ark-ui']} collapsible>
    for (const item of items; key item.value) {
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>
          {item.title}
          <Accordion.ItemIndicator class={styles.ItemIndicator}>
            <ChevronDown />
          </Accordion.ItemIndicator>
        </Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    }
  </Accordion.Root>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

### Multiple

Use the `multiple` prop to allow multiple panels to be expanded simultaneously.

**Example: multiple**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import { ChevronDown } from 'lucide-ripple';
import styles from 'styles/accordion.module.css';

export component Multiple() {
  <Accordion.Root class={styles.Root} defaultValue={['ark-ui']} multiple>
    for (const item of items; key item.value) {
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>
          {item.title}
          <Accordion.ItemIndicator class={styles.ItemIndicator}>
            <ChevronDown />
          </Accordion.ItemIndicator>
        </Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    }
  </Accordion.Root>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

### Horizontal

By default, the Accordion is oriented vertically. Use the `orientation` prop to switch to a horizontal layout.

**Example: horizontal**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import styles from 'styles/accordion.module.css';

export component Horizontal() {
  <Accordion.Root class={styles.Root} defaultValue={['ark-ui']} orientation="horizontal">
    for (const item of items; key item.value) {
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>{item.title}</Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    }
  </Accordion.Root>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

### Lazy Mount

Use the `lazyMount` prop to defer rendering of accordion content until the item is expanded. Combine with
`unmountOnExit` to unmount content when collapsed, freeing up resources.

**Example: lazy-mount**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import { ChevronDown } from 'lucide-ripple';
import styles from 'styles/accordion.module.css';

export component LazyMount() {
  <Accordion.Root class={styles.Root} lazyMount unmountOnExit>
    for (const item of items; key item.value) {
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>
          {item.title}
          <Accordion.ItemIndicator class={styles.ItemIndicator}>
            <ChevronDown />
          </Accordion.ItemIndicator>
        </Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    }
  </Accordion.Root>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

### Context

Use `Accordion.Context` or `useAccordionContext` to access the accordion state.

**Example: context**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import { ChevronDown } from 'lucide-ripple';
import styles from 'styles/accordion.module.css';

export component Context() {
  <Accordion.Root class={styles.Root} defaultValue={['ark-ui']}>
    <Accordion.Context>
      component children({ context }) {
        <output>
          <div>
            {'context.value: '}
            {JSON.stringify(@context.value)}
          </div>
          <div>
            {'context.focusedValue: '}
            {@context.focusedValue || 'null'}
          </div>
        </output>
      }
    </Accordion.Context>
    for (const item of items; key item.value) {
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>
          {item.title}
          <Accordion.ItemIndicator class={styles.ItemIndicator}>
            <ChevronDown />
          </Accordion.ItemIndicator>
        </Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    }
  </Accordion.Root>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

### Item State

Use `Accordion.ItemContext` or `useAccordionItemContext` to access the state of an accordion item.

**Example: item-context**

```ripple
import { Accordion } from 'ark-ripple/accordion';
import { ChevronDown } from 'lucide-ripple';
import styles from 'styles/accordion.module.css';

export component ItemContext() {
  <Accordion.Root class={styles.Root} defaultValue={['ark-ui']}>
    for (const item of items; key item.value) {
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>
          {item.title}
          <Accordion.ItemIndicator class={styles.ItemIndicator}>
            <ChevronDown />
          </Accordion.ItemIndicator>
          <Accordion.ItemContext>
            component children({ context }) {
              <code style="display:inline-flex;gap:0.5rem;font-size:0.75rem">
                if (@context.expanded) {
                  <span>{'Expanded'}</span>
                }
                if (@context.focused) {
                  <span>{'Focused'}</span>
                }
              </code>
            }
          </Accordion.ItemContext>
        </Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    }
  </Accordion.Root>
}

const items = [
  {
    value: 'ark-ui',
    title: 'What is Ark UI?',
    content: 'A headless component library for building accessible web apps.',
  },
  {
    value: 'getting-started',
    title: 'How to get started?',
    content: 'Install the package and import the components you need.',
  },
  {
    value: 'maintainers',
    title: 'Who maintains this project?',
    content: 'Ark UI is maintained by the Chakra UI team.',
  },
];

```

## Guides

### Content Animation

Use the `--height` and/or `--width` CSS variables to animate the size of the content when it expands or closes:

```css
@keyframes slideDown {
  from {
    opacity: 0.01;
    height: 0;
  }
  to {
    opacity: 1;
    height: var(--height);
  }
}

@keyframes slideUp {
  from {
    opacity: 1;
    height: var(--height);
  }
  to {
    opacity: 0.01;
    height: 0;
  }
}

[data-scope='accordion'][data-part='item-content'][data-state='open'] {
  animation: slideDown 250ms ease-in-out;
}

[data-scope='accordion'][data-part='item-content'][data-state='closed'] {
  animation: slideUp 200ms ease-in-out;
}
```

## API Reference

### Props

**Component API Reference**

**Root Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `collapsible` | `boolean` | No | Whether an accordion item can be closed after it has been expanded. |
| `defaultValue` | `string[]` | No | The initial value of the expanded accordion items.
Use when you don't need to control the value of the accordion. |
| `disabled` | `boolean` | No | Whether the accordion items are disabled |
| `id` | `string` | No | The unique identifier of the machine. |
| `ids` | `Partial<{
  root: string
  item: (value: string) => string
  itemContent: (value: string) => string
  itemTrigger: (value: string) => string
}>` | No | The ids of the elements in the accordion. Useful for composition. |
| `lazyMount` | `boolean` | No | Whether to enable lazy mounting |
| `multiple` | `boolean` | No | Whether multiple accordion items can be expanded at the same time. |
| `onFocusChange` | `(details: FocusChangeDetails) => void` | No | The callback fired when the focused accordion item changes. |
| `onValueChange` | `(details: ValueChangeDetails) => void` | No | The callback fired when the state of expanded/collapsed accordion items changes. |
| `orientation` | `'horizontal' | 'vertical'` | No | The orientation of the accordion items. |
| `unmountOnExit` | `boolean` | No | Whether to unmount on exit. |
| `value` | `string[]` | No | The controlled value of the expanded accordion items. |


**Root Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | accordion |
| `[data-part]` | root |
| `[data-orientation]` | The orientation of the accordion |


**ItemContent Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**ItemContent Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | accordion |
| `[data-part]` | item-content |
| `[data-state]` | "open" | "closed" |
| `[data-disabled]` | Present when disabled |
| `[data-focus]` | Present when focused |
| `[data-orientation]` | The orientation of the item |


**ItemIndicator Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**ItemIndicator Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | accordion |
| `[data-part]` | item-indicator |
| `[data-state]` | "open" | "closed" |
| `[data-disabled]` | Present when disabled |
| `[data-focus]` | Present when focused |
| `[data-orientation]` | The orientation of the item |


**Item Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `string` | Yes | The value of the accordion item. |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `disabled` | `boolean` | No | Whether the accordion item is disabled. |


**Item Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | accordion |
| `[data-part]` | item |
| `[data-state]` | "open" | "closed" |
| `[data-focus]` | Present when focused |
| `[data-disabled]` | Present when disabled |
| `[data-orientation]` | The orientation of the item |


**ItemTrigger Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**ItemTrigger Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | accordion |
| `[data-part]` | item-trigger |
| `[data-controls]` |  |
| `[data-orientation]` | The orientation of the item |
| `[data-state]` | "open" | "closed" |


**RootProvider Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `UseAccordionReturn` | Yes |  |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `lazyMount` | `boolean` | No | Whether to enable lazy mounting |
| `unmountOnExit` | `boolean` | No | Whether to unmount on exit. |


### Context

**API:**

| Property | Type | Description |
|----------|------|-------------|
| `focusedValue` | `string` | The value of the focused accordion item. |
| `value` | `string[]` | The value of the accordion |
| `setValue` | `(value: string[]) => void` | Sets the value of the accordion |
| `getItemState` | `(props: ItemProps) => ItemState` | Returns the state of an accordion item. |


## Accessibility

This component complies with the
[Accordion WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/).

### Keyboard Support

<KeyBindingsTable id="accordion" />