Accordion
A collapsible component for displaying content in a vertical stack.
Features
- Full keyboard navigation
- Supports horizontal and vertical orientation
- Right-to-Left (RTL) support
- Single or multiple item expansion
- Controlled and uncontrolled modes
- Collapse each accordion item
Anatomy
To set up the accordion correctly, it's essential to understand its anatomy and the naming of its parts.
Each part includes a
data-part
attribute to help identify them in the DOM.
Examples
Default Expanded State
Set the defaultValue
prop to specify which item should be expanded by default.
Collapsible
Use the collapsible
prop to allow the user to collapse all panels.
import { Accordion } from '@ark-ui/react/accordion'
import { ChevronDownIcon } from 'lucide-react'
export const Collapsible = () => {
return (
<Accordion.Root defaultValue={['React']} collapsible>
{['React', 'Solid', 'Vue'].map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemTrigger>
{item}
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Accordion } from '@ark-ui/solid/accordion'
import { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
export const Collapsible = () => {
return (
<Accordion.Root value={['React']} collapsible>
<Index each={['React', 'Solid', 'Vue']}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>
What is {item()}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item()} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { Accordion } from '@ark-ui/vue/accordion'
import { ref } from 'vue'
import { ChevronDownIcon } from 'lucide-vue-next'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root collapsible>
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>
What is {{ item }}?
<Accordion.ItemIndicator><ChevronDownIcon /></Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{{ item }} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Multiple Panels
Use the multiple
prop to allow multiple panels to be expanded simultaneously.
import { Accordion } from '@ark-ui/react/accordion'
import { ChevronDownIcon } from 'lucide-react'
export const Multiple = () => {
return (
<Accordion.Root defaultValue={['React']} multiple>
{['React', 'Solid', 'Vue'].map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemTrigger>
{item}
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Accordion } from '@ark-ui/solid/accordion'
import { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
export const Multiple = () => {
return (
<Accordion.Root value={['React']} multiple>
<Index each={['React', 'Solid', 'Vue']}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>
What is {item()}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item()} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { Accordion } from '@ark-ui/vue/accordion'
import { ref } from 'vue'
import { ChevronDownIcon } from 'lucide-vue-next'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root multiple>
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>
What is {{ item }}?
<Accordion.ItemIndicator><ChevronDownIcon /></Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{{ item }} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Horizontal Orientation
By default, the Accordion is oriented vertically. Use the orientation
prop to switch to a horizontal layout.
import { Accordion } from '@ark-ui/react/accordion'
import { ChevronDownIcon } from 'lucide-react'
export const Horizontal = () => {
return (
<Accordion.Root defaultValue={['React']} orientation="horizontal">
{['React', 'Solid', 'Vue'].map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemTrigger>
What is {item}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Accordion } from '@ark-ui/solid/accordion'
import { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
export const Horizontal = () => {
return (
<Accordion.Root defaultValue={['React']} orientation="horizontal">
<Index each={['React', 'Solid', 'Vue']}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>
What is {item()}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item()} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { Accordion } from '@ark-ui/vue/accordion'
import { ref } from 'vue'
import { ChevronDownIcon } from 'lucide-vue-next'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root :defaultValue="['React']" orientation="horizontal">
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>
What is {{ item }}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{{ item }} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Animate Content Size
Use the --height
and/or --width
CSS variables to animate the size of the content when it expands or closes:
@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;
}
Using the Root Provider
The RootProvider
component provides a context for the accordion. It accepts the value of the useAccordion
hook.
You can leverage it to access the component state and methods from outside the accordion.
import { Accordion, useAccordion } from '@ark-ui/react/accordion'
import { ChevronDownIcon } from 'lucide-react'
export const RootProvider = () => {
const accordion = useAccordion({ defaultValue: ['React'] })
return (
<>
<button onClick={() => accordion.setValue(['Vue'])}>Set to Vue</button>
<Accordion.RootProvider value={accordion}>
{['React', 'Solid', 'Vue'].map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemTrigger>
What is {item}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.RootProvider>
</>
)
}
import { Accordion, useAccordion } from '@ark-ui/solid/accordion'
import { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
export const RootProvider = () => {
const accordion = useAccordion({ defaultValue: ['React'] })
return (
<>
<button onClick={() => accordion().setValue(['Vue'])}>Set to Vue</button>
<Accordion.RootProvider value={accordion}>
<Index each={['React', 'Solid', 'Vue']}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>
What is {item()}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item()} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.RootProvider>
</>
)
}
<script setup lang="ts">
import { Accordion, useAccordion } from '@ark-ui/vue/accordion'
import { ref } from 'vue'
import { ChevronDownIcon } from 'lucide-vue-next'
const items = ref(['React', 'Solid', 'Vue'])
const accordion = useAccordion({ defaultValue: ['React'] })
</script>
<template>
<button @click="accordion.setValue(['Vue'])">Set to Vue</button>
<Accordion.RootProvider :value="accordion">
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>
What is {{ item }}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{{ item }} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
</Accordion.RootProvider>
</template>
If you're using the
RootProvider
component, you don't need to use theRoot
component.
Acessing the focused item
Use the focusedValue
property to get the value of the focused accordion item.
import { Accordion } from '@ark-ui/react/accordion'
import { ChevronDownIcon } from 'lucide-react'
export const ContextFocusedValue = () => {
return (
<Accordion.Root defaultValue={['React']}>
<Accordion.Context>
{(context) => <span>Focused item: {context.focusedValue}</span>}
</Accordion.Context>
{['React', 'Solid', 'Vue'].map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemTrigger>
What is {item}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Accordion } from '@ark-ui/solid/accordion'
import { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
export const ContextFocusedValue = () => {
return (
<Accordion.Root defaultValue={['React']}>
<Accordion.Context>
{(context) => <span>Focused item: {context().focusedValue}</span>}
</Accordion.Context>
<Index each={['React', 'Solid', 'Vue']}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>
What is {item()}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item()} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { Accordion } from '@ark-ui/vue/accordion'
import { ref } from 'vue'
import { ChevronDownIcon } from '../icons'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root :defaultValue="['React']">
<Accordion.Context v-slot="context">
<span>Focused item: {{ context.focusedValue }}</span>
</Accordion.Context>
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>
What is {{ item }}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{{ item }} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Acessing the selected items
Use the value
property to get the selected accordion items.
import { Accordion } from '@ark-ui/react/accordion'
import { ChevronDownIcon } from 'lucide-react'
export const ContextValue = () => {
return (
<Accordion.Root defaultValue={['React']}>
<Accordion.Context>
{(context) => <span>Selected items: {context.value.join(', ')}</span>}
</Accordion.Context>
{['React', 'Solid', 'Vue'].map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemTrigger>
What is {item}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Accordion } from '@ark-ui/solid/accordion'
import { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
export const ContextValue = () => {
return (
<Accordion.Root defaultValue={['React']}>
<Accordion.Context>
{(context) => <span>Selected items: {context().value.join(', ')}</span>}
</Accordion.Context>
<Index each={['React', 'Solid', 'Vue']}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>
What is {item()}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item()} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { Accordion } from '@ark-ui/vue/accordion'
import { ref } from 'vue'
import { ChevronDownIcon } from '../icons'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root :defaultValue="['React']">
<Accordion.Context v-slot="context">
<span>Selected items: {{ context.value.join(', ') }}</span>
</Accordion.Context>
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>
What is {{ item }}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{{ item }} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Setting the selected items
Use the setValue
method to set the selected accordion items.
import { Accordion } from '@ark-ui/react/accordion'
import { ChevronDownIcon } from 'lucide-react'
export const ContextSetValue = () => {
return (
<Accordion.Root defaultValue={['React']}>
<Accordion.Context>
{(context) => <button onClick={() => context.setValue(['Vue'])}>Select Vue</button>}
</Accordion.Context>
{['React', 'Solid', 'Vue'].map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemTrigger>
What is {item}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Accordion } from '@ark-ui/solid/accordion'
import { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
export const ContextSetValue = () => {
return (
<Accordion.Root defaultValue={['React']}>
<Accordion.Context>
{(context) => <button onClick={() => context().setValue(['Vue'])}>Select Vue</button>}
</Accordion.Context>
<Index each={['React', 'Solid', 'Vue']}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>
What is {item()}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{item()} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { Accordion } from '@ark-ui/vue/accordion'
import { ref } from 'vue'
import { ChevronDownIcon } from '../icons'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root :defaultValue="['React']">
<Accordion.Context v-slot="context">
<button @click="context.setValue(['Vue'])">Select Vue</button>
</Accordion.Context>
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>
What is {{ item }}?
<Accordion.ItemIndicator>
<ChevronDownIcon />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent>
{{ item }} is a JavaScript library for building user interfaces.
</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Accessing an item's state
Use the getItemState
method to get the state of an accordion item.
API Reference
Accessibility
This component complies with the Accordion WAI-ARIA design pattern.
Keyboard Support
Key | Description |
---|---|
Space | When focus is on an trigger of a collapsed item, the item is expanded |
Enter | When focus is on an trigger of a collapsed section, expands the section. |
Tab | Moves focus to the next focusable element |
Shift + Tab | Moves focus to the previous focusable element |
ArrowDown | Moves focus to the next trigger |
ArrowUp | Moves focus to the previous trigger. |
Home | When focus is on an trigger, moves focus to the first trigger. |
End | When focus is on an trigger, moves focus to the last trigger. |