Skip to content
CodeAtlas UI

Surfaces

Accordion

Vertically stacked collapsible sections with one or many items open at once.

<script>
  import { Accordion, AccordionItem } from "@codeatlasdev/ui";
</script>

<Accordion type="single">
  <AccordionItem value="a" title="Question">Answer</AccordionItem>
</Accordion>

Triggers are buttons with aria-expanded. Arrow Up, Arrow Down, Home and End move focus between the enabled triggers, and every trigger stays in the tab order. With type="single" the bound value is a string, with type="multiple" it is a string array.

Single

Only one item is open at a time. Clicking the open item collapses it.

Code
svelte
<script lang="ts">
  import { Accordion, AccordionItem } from '@codeatlasdev/ui';
</script>

<div class="wrap">
  <Accordion type="single">
    <AccordionItem value="a1" title="What is Liquid Glass?">
      Liquid Glass is the opt-in look of the kit: backdrop blur, refraction and tinting on
      surfaces. The default theme is solid.
    </AccordionItem>
    <AccordionItem value="a2" title="Which browsers support backdrop-filter?">
      All modern evergreen browsers. Older environments receive a fallback without the blur effect.
    </AccordionItem>
    <AccordionItem value="a3" title="Can I nest a Surface inside a Card?">
      Yes. A Card is a Surface, so any Surface can sit inside it.
    </AccordionItem>
  </Accordion>
</div>

<style>
  .wrap { width: 100%; max-width: 560px; }
</style>

Multiple

Several items can be open at once.

Code
svelte
<script lang="ts">
  import { Accordion, AccordionItem } from '@codeatlasdev/ui';
</script>

<div class="wrap">
  <Accordion type="multiple">
    <AccordionItem value="b1" title="Svelte 5 runes">
      Runes replace reactive declarations with explicit $state(), $derived() and $effect().
    </AccordionItem>
    <AccordionItem value="b2" title="Headless primitives">
      Unstyled, accessible primitives with the WAI-ARIA patterns built in.
    </AccordionItem>
    <AccordionItem value="b3" title="CSS custom properties">
      All --ca-* tokens are set in global.css and cascade into every component without runtime
      overhead.
    </AccordionItem>
  </Accordion>
</div>

<style>
  .wrap { width: 100%; max-width: 560px; }
</style>

Controlled

Bind `value` to read or set the open item.

Opened from the bound value.

Open item: c1

Code
svelte
<script lang="ts">
  import { Accordion, AccordionItem } from '@codeatlasdev/ui';

  let value = $state<string | string[] | undefined>('c1');
</script>

<div class="wrap">
  <Accordion type="single" bind:value>
    <AccordionItem value="c1" title="First section">Opened from the bound value.</AccordionItem>
    <AccordionItem value="c2" title="Second section">Opening this one closes the first.</AccordionItem>
  </Accordion>
  <p>Open item: {Array.isArray(value) ? value.join(', ') : (value ?? 'none')}</p>
</div>

<style>
  .wrap { width: 100%; max-width: 560px; display: flex; flex-direction: column; gap: var(--ca-space-3); }
  p { margin: 0; font-size: var(--ca-font-size-body2); color: var(--ca-text-secondary); }
</style>

Accordion props

PropTypeDefaultDescription
type'single' | 'multiple''single'Whether one or many items can be open.
valuestring | string[]undefinedOpen item value(s): a string for `single` (`''` when none is open), an array for `multiple`. Bindable.
onValueChange(value: string | string[]) => voidundefinedCalled when the open items change.
classstring''Extra class names on the root.
childrenSnippetundefined`AccordionItem` children.

AccordionItem props

PropTypeDefaultDescription
valuestring–Unique key of the item. Required.
titlestring–Trigger label. Required.
classstring''Extra class names.
childrenSnippetundefinedBody shown when expanded.