Accordion
A set of collapsible panels for FAQs and progressive disclosure, accessible by default. Base UI handles aria-expanded, heading semantics and keyboard navigation.
Default
Only one panel stays open at a time. Pass an array to defaultValue to set the initially expanded item.
import { Accordion } from "@/components/ui/accordion"
export default function Example() {
return (
<div className="flex w-full justify-center">
<Accordion.Root defaultValue={["shipping"]} className="w-full max-w-13">
<Accordion.Item value="shipping">
<Accordion.Trigger>Do you ship internationally?</Accordion.Trigger>
<Accordion.Panel>
Yes. We ship to 140 countries as long as your customs form doesn't
say "definitely not a rocket".
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="returns">
<Accordion.Trigger>What's your return policy?</Accordion.Trigger>
<Accordion.Panel>
30 days, no questions asked. Slightly burnt rocket fuel residue is
still considered "like new".
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="warranty">
<Accordion.Trigger>Is there a warranty?</Accordion.Trigger>
<Accordion.Panel>
Lifetime coverage against spontaneous combustion. Atmospheric
re-entry scratches not included.
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="support">
<Accordion.Trigger>How do I reach support?</Accordion.Trigger>
<Accordion.Panel>
Ping us anytime. Response times range from "instant" to "after we
land" depending on orbital position.
</Accordion.Panel>
</Accordion.Item>
</Accordion.Root>
</div>
)
}Anatomy
Each Accordion.Item wraps a trigger and panel. Set value on every item when you control which panels are open.
import { Accordion } from "@/components/ui/accordion"
<Accordion.Root>
<Accordion.Item>
<Accordion.Trigger />
<Accordion.Panel />
</Accordion.Item>
</Accordion.Root>Multiple
Pass multiple so several panels can stay open together. Use this when readers compare answers across items instead of reading them one at a time.
import { Accordion } from "@/components/ui/accordion"
export default function Example() {
return (
<div className="flex w-full justify-center">
<Accordion.Root multiple defaultValue={["shipping"]} className="w-full max-w-13">
<Accordion.Item value="shipping">
<Accordion.Trigger>Do you ship internationally?</Accordion.Trigger>
<Accordion.Panel>
Yes. We ship to 140 countries as long as your customs form doesn't
say "definitely not a rocket".
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="returns">
<Accordion.Trigger>What's your return policy?</Accordion.Trigger>
<Accordion.Panel>
30 days, no questions asked. Slightly burnt rocket fuel residue is
still considered "like new".
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="warranty">
<Accordion.Trigger>Is there a warranty?</Accordion.Trigger>
<Accordion.Panel>
Lifetime coverage against spontaneous combustion. Atmospheric
re-entry scratches not included.
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="support">
<Accordion.Trigger>How do I reach support?</Accordion.Trigger>
<Accordion.Panel>
Ping us anytime. Response times range from "instant" to "after we
land" depending on orbital position.
</Accordion.Panel>
</Accordion.Item>
</Accordion.Root>
</div>
)
}Disabled
Set disabled on an item to block expansion while keeping the label visible. Use it for sections that are unavailable or require permission.
import { Accordion } from "@/components/ui/accordion"
export default function Example() {
return (
<div className="flex w-full justify-center">
<Accordion.Root defaultValue={["shipping"]} className="w-full max-w-13">
<Accordion.Item value="shipping">
<Accordion.Trigger>Do you ship internationally?</Accordion.Trigger>
<Accordion.Panel>
Yes. We ship to 140 countries as long as your customs form doesn't
say "definitely not a rocket".
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="classified" disabled>
<Accordion.Trigger>Where is the secret launch pad?</Accordion.Trigger>
<Accordion.Panel>
Nice try. This one's classified until you clear the background check.
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="support">
<Accordion.Trigger>How do I reach support?</Accordion.Trigger>
<Accordion.Panel>
Ping us anytime. Response times range from "instant" to "after we
land" depending on orbital position.
</Accordion.Panel>
</Accordion.Item>
</Accordion.Root>
</div>
)
}Borderless
Pass bordered={false} on Accordion.Root to drop dividers between items when the accordion already sits inside a card or list with its own separation.
import { Accordion } from "@/components/ui/accordion"
export default function Example() {
return (
<div className="flex w-full justify-center">
<Accordion.Root bordered={false} defaultValue={["shipping"]} className="w-full max-w-13">
<Accordion.Item value="shipping">
<Accordion.Trigger>Do you ship internationally?</Accordion.Trigger>
<Accordion.Panel>
Yes. We ship to 140 countries as long as your customs form doesn't
say "definitely not a rocket".
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="returns">
<Accordion.Trigger>What's your return policy?</Accordion.Trigger>
<Accordion.Panel>
30 days, no questions asked. Slightly burnt rocket fuel residue is
still considered "like new".
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="warranty">
<Accordion.Trigger>Is there a warranty?</Accordion.Trigger>
<Accordion.Panel>
Lifetime coverage against spontaneous combustion. Atmospheric
re-entry scratches not included.
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="support">
<Accordion.Trigger>How do I reach support?</Accordion.Trigger>
<Accordion.Panel>
Ping us anytime. Response times range from "instant" to "after we
land" depending on orbital position.
</Accordion.Panel>
</Accordion.Item>
</Accordion.Root>
</div>
)
}Props
Accordion.Root
| Prop | Type | Default |
|---|---|---|
| bordered | boolean | true |
| multiple | boolean | false |
| value | string[] | — |
| defaultValue | string[] | — |
| onValueChange | (value: string[], eventDetails) => void | — |
| disabled | boolean | false |
| hiddenUntilFound | boolean | false |
| keepMounted | boolean | false |
Accordion.Item
| Prop | Type | Default |
|---|---|---|
| value | string | auto-generated |
| onOpenChange | (open: boolean, eventDetails) => void | — |
| disabled | boolean | false |
Accordion.Trigger
| Prop | Type | Default |
|---|---|---|
| className | string | — |
| nativeButton | boolean | true |
Accordion.Panel
| Prop | Type | Default |
|---|---|---|
| keepMounted | boolean | false |
| hiddenUntilFound | boolean | false |
This covers the parts used above. See the Base UI Accordion docs for render, event details, CSS variables and data attributes.