Accordion
Use an accordion to show and hide sections of related content on a page, helping users find what they need without overwhelming them. Built with Radix UI primitives for full accessibility.
For a single expandable section, use the Details component instead.
Default Accordion
Only one section can be open at a time. Clicking a new section closes the previously open one.
You will need to provide:
- Proof of identity (passport or driving licence)
- Proof of address (utility bill or bank statement)
- Two passport-sized photographs
import * as Accordion from '@radix-ui/react-accordion';
import { ChevronDown } from 'lucide-react';
<Accordion.Root type="single" defaultValue="item-1" collapsible className="radix-accordion">
<Accordion.Item value="item-1" className="radix-accordion-item">
<Accordion.Header className="radix-accordion-header">
<Accordion.Trigger className="radix-accordion-trigger">
What documents do I need?
<ChevronDown className="radix-accordion-chevron" size={20} />
</Accordion.Trigger>
</Accordion.Header>
<Accordion.Content className="radix-accordion-content">
<div className="radix-accordion-content-inner">
<p>You will need to provide...</p>
</div>
</Accordion.Content>
</Accordion.Item>
...
</Accordion.Root>Accordion vs Details
| Use Accordion when | Use Details when |
|---|---|
| Multiple related sections | Single expandable section |
| Want consistent visual grouping | Inline with other content |
| Need "expand all/collapse all" | Simple show/hide |
| FAQ-style content | Additional context or help text |
Multiple Sections Open
Use type="multiple" to allow multiple sections to be open simultaneously.
import * as Accordion from '@radix-ui/react-accordion';
const [openItems, setOpenItems] = useState<string[]>([]);
const allExpanded = openItems.length === items.length;
<button onClick={() => setOpenItems(allExpanded ? [] : items.map(i => i.id))}>
{allExpanded ? 'Collapse all' : 'Expand all'}
</button>
<Accordion.Root
type="multiple"
value={openItems}
onValueChange={setOpenItems}
className="radix-accordion"
>
...
</Accordion.Root>Controlled vs Uncontrolled
// Uncontrolled - uses defaultValue
<Accordion.Root type="single" defaultValue="item-1" collapsible>
...
</Accordion.Root>
// Controlled - uses value and onValueChange
const [value, setValue] = useState('item-1');
<Accordion.Root type="single" value={value} onValueChange={setValue} collapsible>
...
</Accordion.Root>Accessibility
- Built with Radix UI primitives for full WAI-ARIA compliance
- Keyboard navigation: Enter/Space to toggle, Arrow keys to navigate
- Automatic ARIA attributes (
aria-expanded,aria-controls) - Focus management between accordion items
- Screen reader announces expanded/collapsed state
CSS Classes
/* Radix Accordion */
.radix-accordion { }
.radix-accordion-item { }
.radix-accordion-header { }
.radix-accordion-trigger { }
.radix-accordion-chevron { }
.radix-accordion-content { }
.radix-accordion-content-inner { }
/* Controls */
.accordion-controls { }Installation
npm install @radix-ui/react-accordion lucide-react