Use accordion when labels are enough for quick scanning before expanding.
Accordion
Progressive disclosure pattern for stacked sections of related content.
Overview
- .source-accordion Group wrapper and variant surface
-
.source-accordion-item
Item root using
<details> - .source-accordion-trigger Summary trigger row
- .source-accordion-chevron Open/closed visual indicator
- .source-accordion-content-wrapper Animated content container
States
Design intent
Accordion hides secondary content behind a trigger row. It earns its place when the visible label alone is enough for most users to decide whether they need the detail, and when hiding that detail reduces scanning burden. If the content is something most users need most of the time, keep it visible.
When to use
Write short, descriptive titles so users can choose without opening everything.
Put required actions outside collapsed panels when completion is mandatory.
Do not collapse information that most users need in most sessions.
Avoid generic headings that force users to expand items just to understand them.
Limit nesting. Deeply nested disclosure patterns hurt discoverability.
Variant
Use plain when the parent surface already has structure, bordered for card-like groups, and divided for long stacked FAQ lists.
Designer checklist
- Trigger labels are scannable and self-explanatory without reading the body content.
- Content inside does not include actions the user must complete before proceeding elsewhere.
- Minimum 44px touch target height on mobile.
- Keyboard reaches the trigger with Tab; Enter or Space toggles open and closed.
- Disabled items include a visual or textual explanation of why they are locked.
Accordion props
AccordionItem props
Basic usage
import { Accordion, AccordionItem } from '@pierredelattre/source-react';
<Accordion>
<AccordionItem title="Getting started" defaultOpen>
Install packages and import styles.
</AccordionItem>
<AccordionItem title="Advanced configuration">
Theme overrides and local tokens.
</AccordionItem>
</Accordion>Variant usage
<Accordion variant="divided">
{sections.map((section) => (
<AccordionItem key={section.id} title={section.title}>
{section.content}
</AccordionItem>
))}
</Accordion>