Accordion
A stack of headings that each show and hide a panel, one or several at a time.
Basic
One open at a time; collapsible lets the open one close too.
Click "Forgot password" on the sign in page, enter your email, and follow the link we send. The link expires after one hour.
Yes. Upgrades apply at once; downgrades apply at the end of the billing cycle.
All major credit cards, and invoices for annual plans.
Code
<Accordion value={["reset"]} collapsible>
<AccordionItem value="reset" title="How do I reset my password?">
Click "Forgot password" on the sign in page and follow the email we send.
</AccordionItem>
<AccordionItem value="plan" title="Can I change my subscription plan?">...</AccordionItem>
<AccordionItem value="payment" title="What payment methods do you accept?">...</AccordionItem>
</Accordion>Usage
import { Accordion, AccordionItem } from "@elements/ui/accordion";
<Accordion value={["shipping"]} collapsible>
<AccordionItem value="shipping" title="What are your shipping options?">
Standard shipping takes 5 to 7 business days. Express arrives in 2.
</AccordionItem>
<AccordionItem value="returns" title="What is your return policy?">
Return anything within 30 days for a full refund.
</AccordionItem>
</Accordion>Examples
Multiple
multiple keeps several sections open.
Choose which emails you get: mentions, weekly digests, and product news.
Two factor sign in, active sessions, and data export.
Your plan, invoices, and payment method.
Code
<Accordion multiple value={["notifications"]}>
<AccordionItem value="notifications" title="Notification settings">...</AccordionItem>
<AccordionItem value="privacy" title="Privacy and security">...</AccordionItem>
<AccordionItem value="billing" title="Billing and subscription">...</AccordionItem>
</Accordion>Many sections
multiple with more than six items: the panels drop role=region, so a long settings page does not crowd the landmark list (APG).
Your name, email and avatar.
Password, two factor sign in and sessions.
Mentions, digests and product news.
Plan, invoices and payment method.
Members, roles and invitations.
Connected apps and webhooks.
Exports, retention and deletion.
Code
<Accordion multiple>
<AccordionItem value="account" title="Account">...</AccordionItem>
...seven items: past six, the panels are not regions
</Accordion>Always one open
Without collapsible, the open item stays open (its trigger is aria-disabled) until another opens.
Clicking this heading again does nothing.
Opening this closes the first.
Code
<Accordion value={["one"]}>
<AccordionItem value="one" title="Always one open">...</AccordionItem>
<AccordionItem value="two" title="Open me instead">...</AccordionItem>
</Accordion>Disabled
A disabled item cannot open and arrows skip it. disabled on the root disables every item.
Yes, the last 12 months are under Settings, then Activity.
Only on the Pro plan.
Under Settings, then Account. We send a confirmation to the new address.
Code
<Accordion collapsible disabled={state.allDisabled}>
<AccordionItem value="history" title="Can I access my account history?">...</AccordionItem>
<AccordionItem value="premium" title="Premium feature information" disabled>...</AccordionItem>
<AccordionItem value="email" title="How do I update my email address?">...</AccordionItem>
</Accordion>Bordered
variant=bordered frames the items. These headers are level 4, and loop is off.
Monthly or annual plans, billed on the day you subscribed.
Encrypted at rest and in transit, with daily backups.
Slack, GitHub, Linear and a webhook for everything else.
Code
<Accordion variant="bordered" collapsible loop={false} value={["billing"]}>
<AccordionItem value="billing" level={4} title="How does billing work?">...</AccordionItem>
<AccordionItem value="security" level={4} title="Is my data secure?">...</AccordionItem>
<AccordionItem value="integrations" level={4} title="What integrations do you support?">...</AccordionItem>
</Accordion>In a card, with icons
The trigger slot adds an icon or badge after the title.
Subscription and billing
Common questions about your account, plans and payments.
Starter, Pro and Team. Every plan has a 14 day trial.
Cancel any time from Billing. You keep access until the period ends.
Code
<div class="card">
<h4>Subscription and billing</h4>
<p>Common questions about your account, plans and payments.</p>
<Accordion collapsible value={["plans"]}>
<AccordionItem value="plans" title="What plans are available?">
<Icon slot="trigger" name="star" />
...
</AccordionItem>
</Accordion>
</div>Controlled
Bind value to state. The triggers write it back; onValueChange fires only for their changes.
Alpha.
Bravo.
Charlie.
Code
<Accordion multiple value={state.open} onValueChange={(v) => state.last = v.join(",")}>
...
</Accordion>
<Button onclick={() => state.open = ["a", "b", "c"]}>Open all</Button>
<Button onclick={() => state.open = []}>Close all</Button>Guarded
onValueChange runs before the change with event details (reason, event, cancel). details.cancel() keeps the items as they were until the guard is off.
221B Baker St, London.
Visa ending 4242.
Code
<Accordion collapsible value={state.open} onValueChange={(value, details) => {
if (state.locked) details.cancel();
}}>
<AccordionItem value="x" title="Shipping address">...</AccordionItem>
<AccordionItem value="y" title="Payment">...</AccordionItem>
</Accordion>Item events
onOpenChange on an item fires when a trigger opens or closes that item, including when opening another closes it.
Ships in 2 days.
30 day returns.
Code
<Accordion collapsible>
<AccordionItem value="ship" title="Shipping" onOpenChange={(open) => track("ship", open)}>...</AccordionItem>
<AccordionItem value="returns" title="Returns" onOpenChange={(open) => track("returns", open)}>...</AccordionItem>
</Accordion>Horizontal and right to left
orientation=horizontal moves with Left and Right; dir=rtl flips them.
One.
Two.
Three.
واحد.
اثنان.
ثلاثة.
Code
<Accordion orientation="horizontal" collapsible>...</Accordion>
<Accordion orientation="horizontal" dir="rtl" collapsible>...</Accordion>Find in page
hiddenUntilFound keeps closed panels searchable: find in page, or a link to their text, opens the item.
Every frame carries a lifetime warranty against cracks.
Measure across your current glasses from hinge to hinge.
Code
<Accordion hiddenUntilFound collapsible>
<AccordionItem value="warranty" title="Is there a warranty?">
Every frame carries a lifetime warranty against cracks.
</AccordionItem>
...
</Accordion>Find in page, one item
hiddenUntilFound on an AccordionItem makes only that panel searchable.
Unworn frames go back free within sixty days of delivery.
Single vision and progressive lenses fit every frame we sell.
Code
<Accordion collapsible>
<AccordionItem value="returns" title="Can I return a frame?" hiddenUntilFound>
Unworn frames go back free within sixty days of delivery.
</AccordionItem>
<AccordionItem value="lenses" title="Which lenses fit?">...</AccordionItem>
</Accordion>Generated values
An AccordionItem without value gets a generated one, which the root's value reports.
Every frame ships in a hard case with a cloth.
A second pair is half price at checkout.
Code
<Accordion value={state.open}>
<AccordionItem title="Do frames come with a case?">...</AccordionItem>
<AccordionItem title="Can I add a second pair?">...</AccordionItem>
</Accordion>Nested
An accordion inside a panel drives its own items.
Inside the inner panel.
Same value as the outer item, separate state.
More.
Code
<Accordion collapsible value={["outer"]}>
<AccordionItem value="outer" title="Outer section">
<Accordion collapsible>
<AccordionItem value="inner" title="Inner section">...</AccordionItem>
</Accordion>
</AccordionItem>
</Accordion>Form sections
An accordion splits a form into sections. Submitting with a required field empty in a closed section opens that section, so the browser can point at the field.
Code
<form onsubmit={() => save(state)}>
<Accordion value={["contact"]} collapsible>
<AccordionItem value="contact" title="Contact">...</AccordionItem>
<AccordionItem value="shipping" title="Shipping">
<input name="street" required>
</AccordionItem>
</Accordion>
<Button type="submit">Place order</Button>
</form>