Stacked disclosure rows that expand a single panel at a time or many in parallel.
Description
Accordion is a compound component built on Radix's Accordion primitive. It renders a vertical stack of AccordionItems, each pairing an AccordionTrigger (the clickable header) with an AccordionContent (the expanding panel). A built-in chevron rotates with the open state and a data-state attribute streams from Radix to drive the visuals.
Reach for it when you have a list of disclosure rows that share the same shape, such as FAQ pages, settings groups, nested form sections, and long product specs. Switch type="single" (with optional collapsible) for one-at-a-time reveal, or type="multiple" when the user should be able to open several panels at once. The appearance prop covers six visual treatments, from a borderless ghost-default for in-page FAQs to a card-like outline-rounded or filled-rounded for dense settings panes.
Don't reach for Accordion when you need true tab navigation between sibling views; use Tabs instead. For a single, standalone show/hide region with no list around it, drop down to a Collapsible or Disclosure primitive. For transient, overlay-style content (confirmations, forms that block the page), prefer Dialog or Popover instead.
Installation
Anatomy
Usage
Examples
Ghost Appearance
The three ghost treatments add no card surface around each item. ghost-default is the lightest and works well for inline FAQs. ghost-underline separates rows with a single border, ideal for long lists. ghost-rounded keeps the borderless feel but rounds the open-state surface.
Card Appearance
The card treatments wrap each item in its own surface. outline-rounded is the default card look, with rounded corners, a hairline border, and a soft shadow that clears on hover. outline-sharp is the dense, table-like option with flush corners. filled-rounded swaps the border for a filled background.
Multiple
type="multiple" lets the user open several panels at once and accepts an array value / defaultValue. Pair it with appearance="ghost-underline" when the list is long and you want clear row separators.
With Icon
AccordionTrigger accepts an icon prop that renders a leading glyph next to the label, sized to size-5. The chevron stays anchored to the trailing edge.
With Trailing Content
The trigger forwards children into a flex label slot, so anything you put there sits between the leading icon and the chevron. Push a Badge to the trailing edge with className="ml-auto" to surface status, counts, or severity inline.
Disabled
Set disabled on an AccordionItem to lock it. The trigger becomes non-interactive, the chevron fades to text-disabled, and Radix forwards data-disabled for downstream styling. Setting disabled on the Accordion root disables every item.
Rich Content
AccordionContent accepts any React tree. Use it to nest paragraphs, InlineAlerts, action Buttons, or even forms. The wrapper already supplies flex flex-col gap-4, so direct children stack with consistent spacing.
Accessibility
Accordion delegates focus and ARIA wiring to Radix's Accordion primitive. Each trigger is a real <button> with aria-expanded, aria-controls, and a unique pairing to its content region. The chevron is decorative and not announced.
ARIA notes:
- Each
AccordionItemmust have a uniquevalue; Radix uses it to wirearia-controls/aria-labelledbybetween trigger and content. AccordionContentis rendered as aregionand labelled by its trigger; screen readers announce it when it opens.disableditems are skipped by arrow-key navigation and exposedata-disabledfor styling.- Full keyboard and focus behavior is documented in the Radix Accordion primitive.
Styling
Tailwind override: pass className to merge Tailwind classes with the component's CVA classes (via cn()):
Data slots and attributes: the component sets these for CSS targeting:
data-slot="accordion"on the root element, withdata-appearance="<appearance>".data-slot="accordion-item"on each item wrapper, withdata-state="open" | "closed"anddata-disabled(from Radix).data-slot="accordion-trigger"on the<button>, withdata-stateanddata-disabled.data-slot="accordion-trigger-icon"on the optional leading icon wrapper.data-slot="accordion-trigger-label"on the inner label/flex slot.data-slot="accordion-trigger-chevron"on the trailing chevron SVG (rotates 180° on open).data-slot="accordion-content"on the expanding panel, withdata-state(drives the open/close keyframes).
Target a specific state in CSS:
Related Components
- Tabs: use this when only one panel is ever visible and the labels act as primary navigation between sibling views.
- Collapsible: single, standalone show/hide region without a list around it.
- Dialog: modal overlay for content that should block the page (confirmations, multi-step forms).
- Card: when the content should always be visible and doesn't need to expand or collapse.
API Reference
Accordion
The root container. Wraps Radix's Accordion.Root, broadcasts appearance to nested items, triggers, and content via context, and writes data-slot="accordion" plus data-appearance on the root. Extends React.ComponentProps<typeof Accordion.Root> from radix-ui, so all Radix props (type, collapsible, value, defaultValue, onValueChange, disabled, dir, orientation) are accepted.
Props
Variants
AccordionItem
A single disclosure row. Wraps Radix's Accordion.Item, owns the open-state surface (background, border, hover, focus ring), and writes data-slot="accordion-item". Extends React.ComponentProps<typeof Accordion.Item> from radix-ui.
Props
AccordionTrigger
The clickable header. Wraps Radix's Accordion.Trigger inside Accordion.Header, renders the optional leading icon, a flex label slot, and the trailing chevron. Writes data-slot="accordion-trigger" plus inner slots accordion-trigger-icon, accordion-trigger-label, and accordion-trigger-chevron. Extends React.ComponentProps<typeof Accordion.Trigger> from radix-ui with one extra prop.
Props
AccordionContent
The expanding panel. Wraps Radix's Accordion.Content, applies the registered accordion-down / accordion-up keyframes, and ships a flex flex-col gap-4 inner wrapper so direct children stack with consistent spacing. Writes data-slot="accordion-content". Extends React.ComponentProps<typeof Accordion.Content> from radix-ui.