Skip to main content

Accordion

An accordion is a stack of headed panels that open one at a time (single) or independently (multiple). Headless UI's Disclosure is uncontrolled, so the open set lives in Accordion itself; each trigger is a Headless UI Button inside a heading, wired to a role="region" panel.

import Accordion from '@zuilib/components/accordion'

Single, collapsible

type="single" (the default) keeps one item open. Without collapsible, the open item cannot be closed by its own trigger, per the WAI-ARIA pattern; with it, a second click collapses to none.

Loading example

Variants

bordered is one card with dividers, separated a stack of cards, ghost dividers only. The card variants read their inset from --card-padding (falling back to --card-padding-md), the same property Card uses.

Loading example

Multiple, controlled

type="multiple" types value as string[]. Pass value and onValueChange to own the state.

Loading example

Props

AccordionProps is a union of the single and multiple shapes; both extend div props (minus defaultValue / onChange).

PropTypeDefaultDescription
type'single' | 'multiple''single'Decides whether value is a string or string[]
valuestring | string[]Controlled open item(s); '' means none
defaultValuestring | string[]Uncontrolled initial open item(s)
onValueChange(value: string | string[]) => voidReceives the open item, or '' when a single accordion collapsed
collapsiblebooleanfalsesingle only: allow closing the open item. While false the open trigger is aria-disabled
variant'bordered' | 'separated' | 'ghost''bordered'
disabledbooleanfalseDisables every item
headingLevel2 | 3 | 4 | 5 | 63Heading element wrapping each trigger
classNamestringMerged last onto the root

Accordion.Item

PropTypeDefaultDescription
valuerequiredstringIdentity in value / defaultValue / onValueChange
disabledbooleanfalse
classNamestring

Accordion.Trigger

button props minus type, id, disabled and the aria-expanded / aria-controls / aria-disabled wiring, which come from the item.

PropTypeDefaultDescription
hideChevronbooleanfalseHide the trailing chevron
classNamestringMerged onto the button
headerClassNamestringMerged onto the heading element wrapping the button

Accordion.Content

div props minus id, role and aria-labelledby. The ref and every prop except className land on the animated region wrapper.

PropTypeDefaultDescription
regionbooleantrueExpose the panel as a role="region" landmark labelled by its trigger; pass false on accordions with many panels
unmountbooleanfalseRemove the content from the DOM while closed (after the collapse). Default keeps it mounted and hidden
classNamestringMerged onto the padded body
regionClassNamestringMerged onto the region wrapper

Slots

SlotElementNotes
[data-slot="accordion"]divRoot. Also data-type, data-variant, data-disabled
[data-slot="accordion-item"]divdata-state="open" | "closed", data-disabled
[data-slot="accordion-header"]h2–h6Per headingLevel
[data-slot="accordion-trigger"]buttondata-state; Headless UI data-hover / data-active / data-focus
[data-slot="accordion-title"]spanThe trigger children
[data-slot="accordion-chevron"]svgRotates 180° while open
[data-slot="accordion-content"]divThe animated region; data-state
[data-slot="accordion-content-clip"]divoverflow-hidden during the collapse
[data-slot="accordion-content-body"]divPadded body holding the children

Tokens

TokenUsed for
--card-padding (falls back to --card-padding-md)Trigger and body inset in the card variants
--card, --borderCard surface and dividers
--mutedTrigger hover tint
--ringInset keyboard focus ring
--duration-normal, --ease-standardPanel height and chevron transitions

Accessibility

  • Each trigger is a <button> inside a heading (headingLevel, default h3), with aria-expanded and aria-controls pointing at its panel; the panel is role="region" with aria-labelledby back to the trigger.
  • ArrowDown / ArrowUp move focus between the triggers of one accordion (wrapping); Home / End jump to the first / last. Nested accordions own their own cycle.
  • The open item of a non-collapsible single accordion is aria-disabled but stays focusable, so arrow keys still reach it.
  • The panel animates grid-template-rows from 1fr to 0fr (height to auto); prefers-reduced-motion removes the transition.
  • With unmount, the trigger drops aria-controls while closed since the id no longer exists.
  • Disclosure: a single, uncoordinated panel.
  • Tabs: one visible panel, selected rather than expanded.
  • Card: shares --card-padding with the card variants.