Accordion
A collapsible component for displaying content in a vertical stack.
A collapsible component for displaying content in a vertical stack.
import { ChevronDownIcon } from 'lucide-react'
import { Accordion } from '@ark-ui/react'
export const Basic = () => {
return (
<Accordion.Root>
{['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 { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
import { Accordion } from '@ark-ui/solid'
export const Basic = () => {
return (
<Accordion.Root>
<Index each={['React', 'Solid', 'Vue']}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger onClick={() => console.log('on Click')}>
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 { ref } from 'vue'
import { Accordion } from '@ark-ui/vue'
import { ChevronDownIcon } from 'lucide-vue-next'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root>
<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>
Understanding the Accordion’s anatomy is crucial for proper setup:
Each component part is marked with a
data-part
attribute for easy DOM identification.
You can use CSS animations to create smooth transitions for opening and closing Accordion items. Utilize the data-state
attribute in combination with the --height
CSS variable to animate the open and closed states of Accordion.ItemContent
.
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--height);
}
}
@keyframes slideUp {
from {
height: var(--height);
}
to {
height: 0;
}
}
[data-scope='accordion'][data-part='item-content'][data-state='open'] {
animation: slideDown 250ms;
}
[data-scope='accordion'][data-part='item-content'][data-state='closed'] {
animation: slideUp 200ms;
}
Note: Due to the use of
overflow: hidden
, adding any padding or margins on the content might cause it to “jump”. To avoid this, apply the margin or padding to an inner element within the content.
To create a collapsible Accordion where all panels can be closed simultaneously,
utilize the collapsible
prop:
import { ChevronDownIcon } from 'lucide-react'
import { Accordion } from '@ark-ui/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 { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
import { Accordion } from '@ark-ui/solid'
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 { ref } from 'vue'
import { Accordion } from '@ark-ui/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>
For an Accordion that allows keeping multiple panels open, apply the multiple
prop:
import { ChevronDownIcon } from 'lucide-react'
import { Accordion } from '@ark-ui/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 { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
import { Accordion } from '@ark-ui/solid'
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 { ref } from 'vue'
import { Accordion } from '@ark-ui/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>
For advanced control, access the Accordion API using a function as a child component:
import { Accordion } from '@ark-ui/react'
export const RenderProp = () => {
const items = ['panel-1', 'panel-2', 'panel-3']
return (
<Accordion.Root>
{items.map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemContext>
{(accordionItem) => (
<>
<Accordion.ItemTrigger>
{accordionItem.expanded ? 'Expanded' : 'Closed'}
</Accordion.ItemTrigger>
<Accordion.ItemContent>{item} content</Accordion.ItemContent>
</>
)}
</Accordion.ItemContext>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Index } from 'solid-js'
import { Accordion } from '@ark-ui/solid'
export const RenderProp = () => {
const items = ['panel-1', 'panel-2', 'panel-3']
return (
<Accordion.Root>
<Index each={items}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemContext>
{(api) => (
<>
<Accordion.ItemTrigger>
{api().expanded ? 'Expanded' : 'Closed'}
</Accordion.ItemTrigger>
<Accordion.ItemContent>{item()} content</Accordion.ItemContent>
</>
)}
</Accordion.ItemContext>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { ref } from 'vue'
import { Accordion } from '@ark-ui/vue'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root>
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemContext v-slot="{ expanded }">
<Accordion.ItemTrigger>{{ expanded ? 'Expanded' : 'Closed' }}</Accordion.ItemTrigger>
<Accordion.ItemContent>{{ item }} content</Accordion.ItemContent>
</Accordion.ItemContext>
</Accordion.Item>
</Accordion.Root>
</template>
To manage the Accordion’s state, use the value
prop and update it with the
onValueChange
event:
import { useState } from 'react'
import { Accordion } from '@ark-ui/react'
export const Controlled = () => {
const items = ['panel-1', 'panel-2', 'panel-3']
const [value, setValue] = useState<string[]>([])
return (
<Accordion.Root value={value} onValueChange={(details) => setValue(details.value)}>
{items.map((item) => (
<Accordion.Item key={item} value={item}>
<Accordion.ItemTrigger>{item} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{item} content</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Index, createSignal } from 'solid-js'
import { Accordion } from '@ark-ui/solid'
export const Controlled = () => {
const [value, setValue] = createSignal<string[]>([])
const items = ['panel-1', 'panel-2', 'panel-3']
return (
<Accordion.Root value={value()} onValueChange={(details) => setValue(details.value)}>
<Index each={items}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>{item()} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{item()} content</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { ref } from 'vue'
import { Accordion } from '@ark-ui/vue'
const items = ref(['React', 'Solid', 'Vue'])
const value = ref(['React'])
</script>
<template>
<Accordion.Root v-model="value">
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>{{ item }} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{{ item }} content</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Set the Accordion’s orientation to vertical with the orientation
prop:
import { Accordion } from '@ark-ui/react'
export const Vertical = () => {
const items = ['panel-1', 'panel-2', 'panel-3']
return (
<Accordion.Root orientation="vertical">
{items.map((item) => (
<Accordion.Item key={item} value={item} disabled={item === 'panel-2'}>
<Accordion.ItemTrigger>{item} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{item} content</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Index } from 'solid-js'
import { Accordion } from '@ark-ui/solid'
export const Vertical = () => {
const items = ['panel-1', 'panel-2', 'panel-3']
return (
<Accordion.Root orientation="vertical">
<Index each={items}>
{(item) => (
<Accordion.Item value={item()}>
<Accordion.ItemTrigger>{item()} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{item()} content</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { ref } from 'vue'
import { Accordion } from '@ark-ui/vue'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root orientation="vertical">
<Accordion.Item v-for="item in items" :key="item" :value="item">
<Accordion.ItemTrigger>{{ item }} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{{ item }} content</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Disable any Accordion Item using the disabled
prop:
import { Accordion } from '@ark-ui/react'
export const Disabled = () => {
const items = ['panel-1', 'panel-2', 'panel-3']
return (
<Accordion.Root>
{items.map((item) => (
<Accordion.Item key={item} value={item} disabled={item === 'panel-2'}>
<Accordion.ItemTrigger>{item} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{item} content</Accordion.ItemContent>
</Accordion.Item>
))}
</Accordion.Root>
)
}
import { Index } from 'solid-js'
import { Accordion } from '@ark-ui/solid'
export const Disabled = () => {
const items = ['panel-1', 'panel-2', 'panel-3']
return (
<Accordion.Root>
<Index each={items}>
{(item) => (
<Accordion.Item value={item()} disabled={item() === 'panel-2'}>
<Accordion.ItemTrigger>{item()} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{item()} content</Accordion.ItemContent>
</Accordion.Item>
)}
</Index>
</Accordion.Root>
)
}
<script setup lang="ts">
import { ref } from 'vue'
import { Accordion } from '@ark-ui/vue'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Accordion.Root>
<Accordion.Item v-for="item in items" :key="item" :value="item" :disabled="item === 'Solid'">
<Accordion.ItemTrigger>{{ item }} trigger</Accordion.ItemTrigger>
<Accordion.ItemContent>{{ item }} content</Accordion.ItemContent>
</Accordion.Item>
</Accordion.Root>
</template>
Explore our detailed API Reference for further customization:
Prop | Type | Default |
---|---|---|
asChild Render as a different element type. | boolean | |
collapsible Whether an accordion item can be after it has been expanded. | boolean | false |
defaultValue The initial value of the accordion when it is first rendered.
Use when you do not need to control the state of the color picker. | string[] | |
disabled Whether the accordion items are disabled | boolean | |
id The unique identifier of the machine. | string | |
ids The ids of the elements in the accordion. Useful for composition. | Partial<{
root: string
item(value: string): string
content(value: string): string
trigger(value: string): string
}> | |
lazyMount Whether to enable lazy mounting | boolean | false |
multiple Whether multple accordion items can be expanded at the same time. | boolean | false |
onFocusChange The callback fired when the focused accordion item changes. | (details: FocusChangeDetails) => void | |
onValueChange The callback fired when the state of expanded/collapsed accordion items changes. | (details: ValueChangeDetails) => void | |
orientation The orientation of the accordion items. | 'horizontal' | 'vertical' | "vertical" |
unmountOnExit Whether to unmount on exit. | boolean | false |
value The `value` of the accordion items that are currently being expanded. | string[] |
Prop | Type | Default |
---|---|---|
asChild Render as a different element type. | boolean |
Prop | Type | Default |
---|---|---|
asChild Render as a different element type. | boolean |
Prop | Type | Default |
---|---|---|
value The value of the accordion item. | string | |
asChild Render as a different element type. | boolean | |
disabled Whether the accordion item is disabled. | boolean |
Prop | Type | Default |
---|---|---|
asChild Render as a different element type. | boolean |