Accordion
An accordion that supports single or multiple expansion, optional per-item icons, controlled and uncontrolled modes, grid-based height animation and the WAI-ARIA accordion pattern.
Installation
Add component
pnpm dlx @elyri/cli@latest add accordionExamples
Lined
The default look; items stack with dividers, handy for FAQ lists.
Orders are packed within 24 hours and shipped the next business day. You will get a tracking link by email as soon as the parcel leaves the warehouse.
Yes. Unopened items can be returned within 30 days of delivery for a full refund, no questions asked.
Every product includes a two-year limited warranty.
import { Accordion } from './components/elyri/Accordion';
export function Example() {
return (
<Accordion defaultValue="shipping">
<Accordion.Item value="shipping">
<Accordion.Trigger>When will my order ship?</Accordion.Trigger>
<Accordion.Content>
Orders are packed within 24 hours and shipped the next business day. You will get a tracking link by
email as soon as the parcel leaves the warehouse.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="returns">
<Accordion.Trigger>Can I return a purchase?</Accordion.Trigger>
<Accordion.Content>
Yes. Unopened items can be returned within 30 days of delivery for a full refund, no questions asked.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="warranty" disabled>
<Accordion.Trigger>Is there a warranty?</Accordion.Trigger>
<Accordion.Content>Every product includes a two-year limited warranty.</Accordion.Content>
</Accordion.Item>
</Accordion>
);
}Separated
Each item is a card; the open one lights up its border and floats with a shadow.
Open Settings, choose Security, then click Reset password. We email you a link that stays valid for one hour.
Every invoice lives under Billing → History and can be downloaded as a PDF at any time.
Workspace owners can invite unlimited members from the Team page. Roles control what each member can change.
import { Accordion } from './components/elyri/Accordion';
export function Example() {
return (
<Accordion defaultValue="account" variant="separated">
<Accordion.Item value="account">
<Accordion.Trigger>How do I reset my password?</Accordion.Trigger>
<Accordion.Content>
Open Settings, choose Security, then click Reset password. We email you a link that stays valid for
one hour.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="billing">
<Accordion.Trigger>Where are my invoices?</Accordion.Trigger>
<Accordion.Content>
Every invoice lives under Billing → History and can be downloaded as a PDF at any time.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="team">
<Accordion.Trigger>Can I invite my team?</Accordion.Trigger>
<Accordion.Content>
Workspace owners can invite unlimited members from the Team page. Roles control what each member can
change.
</Accordion.Content>
</Accordion.Item>
</Accordion>
);
}Collapsible
With collapsible enabled, clicking the open item again folds it away.
Run npx @elyri/cli add accordion and the component source is copied straight into your project.
Yes. Every color, radius and shadow comes from CSS variables, so overriding a handful of tokens reskins the whole component.
import { Accordion } from './components/elyri/Accordion';
export function Example() {
return (
<Accordion defaultValue="install" collapsible>
<Accordion.Item value="install">
<Accordion.Trigger>How do I install Elyri?</Accordion.Trigger>
<Accordion.Content>
Run npx @elyri/cli add accordion and the component source is copied straight into your project.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="theme">
<Accordion.Trigger>Can I restyle it?</Accordion.Trigger>
<Accordion.Content>
Yes. Every color, radius and shadow comes from CSS variables, so overriding a handful of tokens
reskins the whole component.
</Accordion.Content>
</Accordion.Item>
</Accordion>
);
}Multiple + icons
type="multiple" lets several items stay open; the icon prop adds a leading icon to a title.
Colors, radii and shadows all read from CSS variables, so a theme change is a handful of overrides.
tsup emits ESM, CJS and type declarations for every package on each build.
Triggers expose aria-expanded and panels become labelled regions, matching the WAI-ARIA pattern.
import { Accordion } from './components/elyri/Accordion';
const SparkIcon = (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M12 3v18M3 12h18M5.6 5.6l12.8 12.8M18.4 5.6 5.6 18.4" />
</svg>
);
export function Example() {
return (
<Accordion type="multiple" defaultValue={['design', 'build']} variant="separated">
<Accordion.Item value="design">
<Accordion.Trigger icon={SparkIcon}>Design tokens</Accordion.Trigger>
<Accordion.Content>
Colors, radii and shadows all read from CSS variables, so a theme change is a handful of overrides.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="build">
<Accordion.Trigger icon={SparkIcon}>Build pipeline</Accordion.Trigger>
<Accordion.Content>tsup emits ESM, CJS and type declarations for every package on each build.</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="a11y">
<Accordion.Trigger icon={SparkIcon}>Accessibility</Accordion.Trigger>
<Accordion.Content>
Triggers expose aria-expanded and panels become labelled regions, matching the WAI-ARIA pattern.
</Accordion.Content>
</Accordion.Item>
</Accordion>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'single' | 'multiple' | 'single' | Expansion mode: single (one item at a time) or multiple (several at once) |
value | string | string[] | — | Controlled expanded value; a string[] when multiple |
defaultValue | string | string[] | — | Initial value when uncontrolled; a string[] when multiple |
onValueChange | (value: string | string[]) => void | — | Called on every change; the signature follows type (string / string[]) |
collapsible | boolean | false | Allows clicking the open item again to collapse it (multiple is always collapsible) |
variant | 'lined' | 'separated' | 'lined' | Appearance: lined (stacked with dividers) or separated (standalone cards) |
Accordion.Item | { value: string; disabled?: boolean } & HTMLAttributes | — | A single item; its value links the trigger and the panel, and it can be disabled |
Accordion.Trigger | { icon?: ReactNode } & ButtonHTMLAttributes | — | The heading button, wrapped in an h3; icon renders a leading icon |
Accordion.Content | HTMLAttributes | — | Panel kept in the DOM, only hidden while collapsed |
...rest | HTMLAttributes | — | Remaining props are forwarded to the native div |