Accordion
Import
Section titled “Import”import { Accordion, AccordionItem } from '@delightstack/components';Basic Usage
Section titled “Basic Usage”View code
<script> import { Accordion, AccordionItem } from '@delightstack/components';
let openSection = $state('faq-1');</script>
<Accordion bind:value={openSection}> <AccordionItem value="faq-1" title="Getting Started"> <p>Getting started is easy! Create an account and follow the onboarding steps.</p> </AccordionItem>
<AccordionItem value="faq-2" title="Payment Methods"> <p>We accept all major credit cards, PayPal, and bank transfers.</p> </AccordionItem>
<AccordionItem value="faq-3" title="Contact Support"> <p>Reach our support team via email or through the in-app chat.</p> </AccordionItem></Accordion>Examples
Section titled “Examples”Variants
Section titled “Variants”By default an accordion is borderless — just a subtle hairline between items (and none after the
last one), with items sitting flush against each other. Add filled to join the items into one
tinted surface, or outline to wrap the whole set in a single bordered, rounded frame. Corners
follow the library’s squircle treatment.
filled and outline are independent, so you can combine them for a framed set of filled items.
Default
Filled
Outline
View code
<!-- Default: hairline separators only --><Accordion value="a">…</Accordion>
<!-- Filled: items join into one tinted surface --><Accordion filled value="a">…</Accordion>
<!-- Outline: a single bordered, rounded frame --><Accordion outline value="a">…</Accordion>Separated Panels
Section titled “Separated Panels”By default items stay connected. Add separated and the open item animates apart from the list,
gaining a gap above and below so the active section reads as emphasised. With filled or outline
this is especially nice: the single surface starts connected and splits into rounded pieces as
an item opens — the item above rounds its bottom corners, the active item rounds all four, and the
item below rounds its top corners. Closing the item glides everything back into one piece.
Outline + separated
Filled + separated
View code
<!-- Outline frame that splits apart on open --><Accordion outline separated value="b">…</Accordion>
<!-- Filled surface that splits apart on open --><Accordion filled separated value="b">…</Accordion>Multiple Panels Open
Section titled “Multiple Panels Open”Allow multiple sections to be expanded simultaneously. When multiple is true, value is an array of strings.
View code
<script> let openSections = $state(['section-1']);</script>
<Accordion multiple bind:value={openSections}> <AccordionItem value="section-1" title="First Section"> <p>Content for the first section.</p> </AccordionItem> <AccordionItem value="section-2" title="Second Section"> <p>Content for the second section.</p> </AccordionItem> <AccordionItem value="section-3" title="Third Section"> <p>Content for the third section.</p> </AccordionItem></Accordion>Always One Open
Section titled “Always One Open”Prevent all sections from being collapsed by setting collapsible to false.
View code
<Accordion collapsible={false} value="first"> <AccordionItem value="first" title="Always Visible"> <p>At least one section is always open.</p> </AccordionItem> <AccordionItem value="second" title="Another Section"> <p>Click to switch which section is open.</p> </AccordionItem></Accordion>Custom Trigger
Section titled “Custom Trigger”Use the trigger snippet to replace the default title rendering with custom content.
View code
<script> import { Accordion, AccordionItem } from '@delightstack/components';
let value = $state('settings');</script>
<Accordion bind:value> <AccordionItem value="profile"> {#snippet trigger()} <div style="display: flex; align-items: center; gap: 0.5rem;"> <UserIcon /> <span>Profile Settings</span> </div> {/snippet} <p>Manage your name, avatar, and public profile information.</p> </AccordionItem>
<AccordionItem value="settings"> {#snippet trigger()} <div style="display: flex; align-items: center; gap: 0.5rem;"> <SettingsIcon /> <span>Advanced Settings</span> </div> {/snippet} <p>Configure advanced options like API keys, webhooks, and integrations.</p> </AccordionItem></Accordion>Dense and Comfortable Spacing
Section titled “Dense and Comfortable Spacing”Dense
Comfortable
View code
<!-- Compact spacing --><Accordion dense> <AccordionItem value="a" title="Compact Item A"> <p>Less padding for dense layouts.</p> </AccordionItem> <AccordionItem value="b" title="Compact Item B"> <p>Tighter spacing between items.</p> </AccordionItem></Accordion>
<!-- Relaxed spacing --><Accordion comfortable> <AccordionItem value="a" title="Spacious Item A"> <p>More padding for a relaxed feel.</p> </AccordionItem> <AccordionItem value="b" title="Spacious Item B"> <p>Extra breathing room between items.</p> </AccordionItem></Accordion>Skeleton Loading
Section titled “Skeleton Loading”View code
<Accordion skeleton={loading} skeleton_count={3}>…</Accordion>Nested Accordions
Section titled “Nested Accordions”View code
<script> import { Accordion, AccordionItem } from '@delightstack/components';
let outerValue = $state('parent-1'); let innerValue = $state('');</script>
<Accordion bind:value={outerValue}> <AccordionItem value="parent-1" title="Frontend Frameworks"> <Accordion bind:value={innerValue}> <AccordionItem value="child-1" title="Svelte"> <p>A compiler-based framework that shifts work to build time.</p> </AccordionItem> <AccordionItem value="child-2" title="React"> <p>A library for building user interfaces with a virtual DOM.</p> </AccordionItem> </Accordion> </AccordionItem> <AccordionItem value="parent-2" title="Backend Languages"> <p>Popular choices include Node.js, Python, Go, and Rust.</p> </AccordionItem></Accordion>Accordion
Section titled “Accordion”| Prop | Type | Default | Description |
|---|---|---|---|
value | string | string[] | '' | Currently open item(s), bindable |
multiple | boolean | false | Allow multiple panels open simultaneously |
collapsible | boolean | true | Allow closing all items |
disabled | boolean | false | Disable all items |
dense | boolean | false | Compact header/content padding |
comfortable | boolean | false | Relaxed header/content padding |
filled | boolean | false | Join items into one subtly tinted, rounded surface |
outline | boolean | false | Wrap the whole set in a single bordered, rounded (squircle) frame |
separated | boolean | false | Animate the open item apart from the list; with filled/outline the surface splits into rounded pieces |
skeleton | boolean | false | Show loading skeleton |
skeleton_count | number | 3 | Number of skeleton items to render |
id | string | auto | Element ID |
class | string | '' | Additional CSS classes |
children | Snippet | - | AccordionItem children |
AccordionItem
Section titled “AccordionItem”| Prop | Type | Default | Description |
|---|---|---|---|
value | string | required | Unique identifier for this item |
title | string | '' | Header text shown in the summary |
disabled | boolean | false | Disable this individual item |
trigger | Snippet | - | Custom header content replacing title text |
children | Snippet | - | Panel content |
Accessibility
Section titled “Accessibility”- Uses semantic
<details>/<summary>elements for native accessibility aria-expandedon each<summary>reflects its open/closed statearia-controlslinks each<summary>to its content panelrole="region"on each content panel witharia-labelledby- Tab moves focus between summary elements
- Arrow Down / Arrow Up moves focus to next/previous summary
- Enter / Space toggles the focused item
- Home moves focus to the first summary
- End moves focus to the last summary
- Disabled items are excluded from arrow key navigation
- Respects
prefers-reduced-motionfor chevron transitions