dssoca docs
GitHub repository

Accordion

Collapsible sections with one or many open at a time.

A vertically stacked set of collapsible sections. Each item is a heading-wrapped `<button>` toggle (label + optional hint + a chevron that rotates 180° on open) over an animated content `region`. Single-open by default; `multiple` lets several stay open. Works uncontrolled (`defaultValue`) or controlled (bindable `value` + `onChange`). The reveal uses the `--ss-dur` / `--ss-ease` motion tokens and collapses instantly under `prefers-reduced-motion`.

Demo

live · storybook Open in Storybook

Demo loads from https://dssoca-storybook.vercel.app/. Run pnpm storybook for it to render locally.

Usage

svelte
<script>
  import { Accordion } from 'dssoca';

  const items = [
    { id: 'shipping', label: 'Shipping' },
    { id: 'returns', label: 'Returns', hint: '30 days' },
  ];
</script>

<Accordion {items} defaultValue="shipping">
  {#snippet panel(item)}
    <p>Content for {item.label}.</p>
  {/snippet}
</Accordion>

Each header is a real `<button>` with `aria-expanded` + `aria-controls`; the panel is a `role="region"` labelled by its header (`aria-labelledby`). Enter/Space toggle; ArrowUp/ArrowDown move between headers (wrapping), Home/End jump to the first/last. Disabled sections use `aria-disabled` so they stay reachable by keyboard but do not toggle. The toggle chevron is the shared `Icon` `chevron` glyph (DS-0110) — `aria-hidden`, inside the header button — rotating 180° on open; the Accordion resolves its size once and passes it explicitly to that Icon (DS-0111), so a sm/md/lg Accordion gets a matching chevron, text, and spacing. The panel content is laid out as an always-padded block inside the grid-rows reveal clip, so it animates open as a stable padded block with no mid-animation reflow (DS-0115). Use `overflow="truncate"` to keep a long header label on a single line with an ellipsis (default `wrap`); a custom `header` snippet owns its own overflow handling. Zero border-radius; padding/typography scale with the size axis. WCAG 2.2 AA.

Props

PropTypeDefaultDescription
itemsAccordionItem[]Required. Sections — each `{ id, label, hint?, disabled? }`.
panelSnippet<[AccordionItem]>Required. Renders the content for each section; receives the item.
headerSnippet<[AccordionItem]>Optional custom header content (replaces the default label + hint).
multiplebooleanfalseAllow several sections open at once; otherwise opening one closes the others.
valuestring | string[]Controlled, bindable open state — an id (single) or list of ids (`multiple`).
defaultValuestring | string[]Initial open section(s) when uncontrolled.
onChange(value) => voidFired with the new open value whenever a section toggles.
overflow'truncate' | 'wrap''wrap'How a long header label behaves when it exceeds the available width. `wrap` (default) flows onto multiple lines; `truncate` keeps it on a single line with an ellipsis. Applies to the default header markup only.
headingLevel1 | 2 | 3 | 4 | 5 | 63Heading level wrapping each header button (document outline).
idBasestringBase id used to namespace the generated header/panel ids. Defaults to a stable per-instance id (from `$props.id()`) so server- and client-rendered IDs match (SSR-safe).
size'sm' | 'md' | 'lg'Per-instance size override; inherits the ancestor `data-size-variant` when unset.