Accordion
Vertical stack of expandable sections. Single or multiple open at once, with built-in keyboard navigation.
Overview
Accordion is the coordinated-disclosure primitive: a vertical stack of sections where readers expand and collapse to reveal content in place. Built on Radix Accordion, it ships two modes via type: "single" (one open at a time, optionally with collapsible so the open item can also close) and "multiple" (any number open simultaneously).
Reach for Accordion when siblings should remain visible - the vertical context is preserved, so readers can scan headings without losing their place. When you want full context swaps, use Tabs instead. Don't nest more than two levels deep; depth past that becomes a scavenger hunt.
For a single, isolated "show more" toggle, prefer Collapsible - it's the building block Accordion is composed on.
Preview
Installation
bash npx gremorie@latest add rx-accordion bash pnpm dlx gremorie@latest add rx-accordion bash yarn dlx gremorie@latest add rx-accordion bash bunx --bun gremorie@latest add rx-accordion Usage
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "@gremorie/rx-display";
export function Example() {
return (
<Accordion type="single" collapsible defaultValue="item-1">
<AccordionItem value="item-1">
<AccordionTrigger>What is the registry?</AccordionTrigger>
<AccordionContent>
The single source of truth for Gremorie primitives.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>What does the MCP server do?</AccordionTrigger>
<AccordionContent>
Exposes the registry as MCP tools.
</AccordionContent>
</AccordionItem>
</Accordion>
);
}Angular edition planned for Phase 5h. Star the repo to track progress.
API
<Accordion>
Wraps Radix Accordion.Root.
| Prop | Type | Default | Description |
|---|---|---|---|
type | "single" | "multiple" | - | Required. "single" lets one item open at a time; "multiple" lets any number open. |
collapsible | boolean | false | Only with type="single". When true, clicking the open item closes it. |
value | string | string[] | - | Controlled value(s) of the open item(s). string for single, string[] for multiple. |
defaultValue | string | string[] | - | Uncontrolled default. |
onValueChange | (value: string | string[]) => void | - | Fires when an item opens or closes. |
disabled | boolean | false | Disables all items. |
orientation | "vertical" | "horizontal" | "vertical" | Affects keyboard navigation (Arrow keys). |
dir | "ltr" | "rtl" | "ltr" | Reading direction. |
<AccordionItem>
A single section. Wraps Radix Accordion.Item.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | Required. Unique identifier - this is what value / defaultValue on Root references. |
disabled | boolean | false | Disables this specific item. |
Renders with border-b last:border-b-0 for clean stacking.
<AccordionTrigger>
The clickable header. Wraps Radix Accordion.Trigger inside an Accordion.Header for proper semantics. Includes a ChevronDown icon that rotates 180 degrees when the item opens ([&[data-state=open]>svg]:rotate-180).
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Extra classes merged via cn. |
<AccordionContent>
The collapsible content panel. Animates open and closed using data-[state=closed]:animate-accordion-up and data-[state=open]:animate-accordion-down. Wraps content in an inner div with pt-0 pb-4.
Composition
<Accordion>owns the state (type, controlledvalueor uncontrolleddefaultValue).- One or more
<AccordionItem>with uniquevalueprops. - Inside each item: an
<AccordionTrigger>(the header) followed by<AccordionContent>(the body).
The Trigger renders inside an internal Accordion.Header so the heading semantics are correct - you do not need to wrap the trigger in your own <h3>.
Variations
Single-open FAQ
<Accordion type="single" collapsible>
<AccordionItem value="q1">
<AccordionTrigger>Is it accessible?</AccordionTrigger>
<AccordionContent>
Yes. Built on Radix Accordion with full WAI-ARIA support.
</AccordionContent>
</AccordionItem>
<AccordionItem value="q2">
<AccordionTrigger>Is it animated?</AccordionTrigger>
<AccordionContent>
Yes, height-aware open and close animations.
</AccordionContent>
</AccordionItem>
</Accordion>Multiple sections open
<Accordion type="multiple" defaultValue={['release-1', 'release-2']}>
<AccordionItem value="release-1">
<AccordionTrigger>v1.0 - Initial release</AccordionTrigger>
<AccordionContent>57 primitives across 8 packages.</AccordionContent>
</AccordionItem>
<AccordionItem value="release-2">
<AccordionTrigger>v1.1 - AI primitives</AccordionTrigger>
<AccordionContent>Added Message, Prompt, Response.</AccordionContent>
</AccordionItem>
</Accordion>Controlled value
const [open, setOpen] = useState<string>('billing');
<Accordion type="single" collapsible value={open} onValueChange={setOpen}>
<AccordionItem value="account">
<AccordionTrigger>Account</AccordionTrigger>
<AccordionContent>...</AccordionContent>
</AccordionItem>
<AccordionItem value="billing">
<AccordionTrigger>Billing</AccordionTrigger>
<AccordionContent>...</AccordionContent>
</AccordionItem>
</Accordion>;Accessibility
- WAI-ARIA Accordion pattern: Radix sets
role="region"on each content panel witharia-labelledbypointing at its trigger; the trigger getsaria-expandedandaria-controls. - Keyboard:
Tabmoves between triggers;SpaceorEntertoggles the focused trigger;ArrowDown/ArrowUpnavigate between triggers (loops at the ends).HomeandEndjump to first and last. - Headings: each trigger is wrapped in an internal
Accordion.Header(renders as a<h3>by default) so screen readers announce the section as a heading. - Disabled items: render with
aria-disabled="true"and are skipped during arrow-key navigation. - Reduced motion: animations use
data-[state]selectors withprefers-reduced-motionqueries inherited from the keyframes config.
Related
- Collapsible - the single-section building block Accordion is composed on.
- Tabs - use when readers should context-swap rather than browse siblings.
- Card - common host for an Accordion inside a settings panel.