Accordion ported
Progressively reveal supporting information in place.
A single-open, collapsible list of question and answer rows built on Bits UI with spring-animated panel disclosure.
Loading demo…
Guidance
When to use
- FAQ sections where only one answer should be open at a time.
- Settings or help pages that group long content under short, scannable questions.
- Page-level FAQs that need larger type, via size="lg".
When not to use
- Use Expandable Card for a single standalone disclosure such as a plan or order summary.
- Use Tabs when sections are peer views that people switch between.
- Use Onboarding Checklist when the rows are setup tasks to complete.
pnpm dlx shadcn-svelte@latest add @arcui/accordionUsage
<script lang="ts">
import Accordion from '$lib/components/accordion/accordion.svelte';
const items = [
{ title: 'Can I cancel anytime?', content: cancelAnswer },
{ title: 'Do you offer refunds?', content: refundAnswer }
];
</script>
<Accordion size="lg" {items} />
{#snippet cancelAnswer()}
<p>Yes. Your plan stays active until the billing period ends.</p>
{/snippet}
{#snippet refundAnswer()}
<p>Within 14 days of purchase, no questions asked.</p>
{/snippet}Variants & Examples
Default (size="md")
Compact row height with standard question typography for cards or sidebars.
<Accordion {items} />Large (size="lg")
Expanded row height with large question headings and a 62ch max-width for page-level FAQs.
<Accordion {items} size="lg" />All Closed on First Render
Pass defaultOpen={-1} to start with all items collapsed.
<Accordion {items} defaultOpen={-1} />API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
items | { title: string; content?: Snippet }[] | — | Ordered rows. The title is the trigger button label; content is a Svelte 5 Snippet rendering the panel body. |
defaultOpen | number | 0 | Index of the row open on first render. Pass -1 to start with every row closed. |
size | 'md' | 'lg' | 'md' | "lg" sets questions at the large text size for page-level FAQs with responsive padding. |
Keyboard Interactions
| Key | Action |
|---|---|
Enter / Space | Toggles the focused accordion row. |
ArrowDown | Moves focus to the next accordion trigger. |
ArrowUp | Moves focus to the previous accordion trigger. |
Home | Jumps focus directly to the first trigger. |
End | Jumps focus directly to the last trigger. |
Accessibility
- Bits UI wires aria-expanded, aria-controls, and region labelling between each trigger and panel.
- Closed panels stay mounted in the DOM but switch to visibility: hidden once collapsed, cleanly leaving the accessibility tree.
- Triggers sit inside h3 heading elements (level 3, matching the React original); the chevron icon is aria-hidden="true".
- Keyboard navigation conforms to the WAI-ARIA Accordion design pattern with automatic looping/boundary handling.
Motion
Phase 1 still-state: closed panels hold at height 0 / opacity 0 / visibility hidden while staying mounted; the chevron sits at its rotation end value (0deg vs 180deg). Phase 2 wires the non-overshooting height spring, blur settle (slides down 6px out of a subtle blur), and snappy icon spring via @humanspeak/svelte-motion; mid-flight toggles retarget smoothly without restarting. Reduced-motion applies the same end states instantly in one step.
Notes for AI
- Use for FAQs and settings groups where only one section should be open. Use expandable-card for single disclosures and tabs when sections are peers.
- Content is passed via Svelte 5 snippets ({#snippet answer()}...{/snippet}) rather than ReactNode.
- Pass defaultOpen={-1} if you need all accordion items to be collapsed on initial render.
- Only single-expand mode is supported by design to keep disclosure focused.
Source of truth: registry/components/accordion/accordion.tsx