Skip to content

Accordion

Stable

A stack of headings that each reveal a section of content — progressive disclosure for secondary information.

Anatomy

  1. 1TriggerA button inside a heading that names the section. The whole row toggles it.
  2. 2ItemOne section: a trigger and its panel. Hairlines separate the items.
  3. 3IconPoints down while the section is closed and turns over when it opens.
  4. 4PanelThe section's content. It animates its height open and closed, and stays out of the tab order while closed.

Installation

$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/accordion.json

Usage

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion"
<Accordion defaultValue={["shipping"]}>
  <AccordionItem value="shipping">
    <AccordionTrigger>How long does shipping take?</AccordionTrigger>
    <AccordionContent>Orders ship within one business day.</AccordionContent>
  </AccordionItem>
</Accordion>

defaultValue and value are always arrays of item values — even when only one item can be open. Give every item a stable value so its state survives re-renders and can be controlled.

Examples

FAQ

The classic use: many questions, few of them relevant to any one reader. One item opens at a time by default, so the list stays short and scannable as people move between answers.

Frequently asked questions

Everything about plans, billing and your data.

Multiple open

Set multiple when people need to compare or work across sections at the same time — filters, settings, grouped form options. Here two filter groups start open.

With icons and summaries

Triggers accept any inline content. A leading icon and a one-line summary let people decide whether to open a section without opening it. Indent the panel (className on AccordionContent styles its inner wrapper) so body text aligns with the title.

Disabled item

Disable an item that exists but isn't available, and say why in the label. The trigger stays visible, is announced as disabled and can't be toggled.

Controlled

Control value to open sections from elsewhere — Expand all, deep links, or restoring what someone had open. onValueChange receives the next array of open values.

1 of 3 expanded

const [value, setValue] = React.useState<string[]>(["install"])

<Accordion multiple value={value} onValueChange={setValue}>

</Accordion>

Motion

Panels animate their real height with the base duration and standard easing, and fade their content in the same beat; the chevron rotates in step. Nothing is scaled or clipped, so text never smears. With prefers-reduced-motion, sections open instantly.

Guidelines

When to use

  • To shorten long pages whose sections are relevant to only some readers: FAQs, product details, release notes.
  • To group related settings or filters that people revisit selectively.
  • On small screens, to keep secondary content one tap away instead of scrolled past.

When not to use

  • For content everyone needs. Hiding it costs a click and hurts findability — show it.
  • For a single show/hide region — use a Collapsible.
  • To switch between views of the same data — use Tabs.
  • For navigation — use a Sidebar or Navigation Menu.

Write triggers people can scan

Triggers are headings. Keep them short, front-load the keyword, and make them mutually exclusive so people can tell which one holds their answer. In an FAQ, phrase them as the question the reader would ask.

Do.Short, specific headings that predict what's inside.

Don’t.Vague labels force people to open every section to find anything.

Keep it flat

Don't nest accordions. A second level of disclosure hides content behind two clicks and makes the open/closed state hard to follow. If the content needs hierarchy, give it its own page.

Never hide what decides the task

Prices, errors, required fields and anything that changes a decision must stay visible. An accordion is for supporting content; if closing a section could make someone miss something important, it shouldn't be in one.

Accessibility

Each trigger is a <button> inside an <h3>, with aria-expanded and aria-controls pointing at its panel. Panels have role="region" and are labelled by their trigger, so screen readers announce which section they're in.

KeyBehavior
Tab
Moves focus to the next trigger, or into the open panel's focusable content.
ShiftTab
Moves focus to the previous trigger or focusable element.
EnterSpace
Expands or collapses the focused section.
  • No arrow-key navigation. Following the 2025 update to the WAI-ARIA Authoring Practices, accordion headers are ordinary tab stops; arrow keys are not intercepted.
  • Heading level. Triggers sit in an <h3>. If that breaks your page outline, change the render of AccordionPrimitive.Header in your copy of the component (for example render={<h2 />}).
  • Find in page. Set hiddenUntilFound on the root (or a panel) and the browser's find-in-page can search closed sections and open them on a match.
  • Disabled items stay in the reading order and are announced as disabled, so people know the section exists.

API reference

Accordion

Groups the items and manages which are open. Renders a <div>. Accepts every prop of Base UI Accordion.Root.

PropTypeDefault
defaultValue

Values of the items open on first render (uncontrolled).

any[]No default
value

Values of the open items (controlled). Pair with onValueChange.

any[]No default
onValueChange

Called with the next array of open values when an item is toggled.

(value: any[], details) => voidNo default
multiple

Allows more than one item to be open at the same time.

booleanfalse
disabled

Disables every item.

booleanfalse
hiddenUntilFound

Keeps closed panels in the DOM with hidden="until-found" so find-in-page can reveal them.

booleanfalse
keepMounted

Keeps closed panels in the DOM. Ignored when hiddenUntilFound is set.

booleanfalse

AccordionItem

One heading and its panel. Renders a <div>.

PropTypeDefault
value

Identifies the item in value and defaultValue. Generated when omitted — set it whenever you control the accordion.

anyNo default
disabled

Prevents the item from being toggled.

booleanfalse
onOpenChange

Called when this item opens or closes.

(open: boolean, details) => voidNo default

AccordionTrigger

The button that toggles its item, wrapped in an <h3>. Includes the rotating chevron. Accepts every prop of Base UI Accordion.Trigger.

AccordionContent

The collapsible panel. className applies to the inner content wrapper (padding, typography), while the outer panel handles the height animation. Accepts every prop of Base UI Accordion.Panel, including hiddenUntilFound and keepMounted.