Skip to main content
Urbicon UI

Accordion

Collapsible content sections with expand/collapse animation. Supports single or multiple open items, three visual variants, keyboard navigation, and full ARIA accordion pattern.

Playground

Design tokens are named values — colors, spacing, radii — that form the single source of truth for your design system.

Semantic tokens map to foundation tokens. Swap the foundation layer and the entire UI updates automatically.

Yes — semantic tokens handle dark mode via the CSS light-dark() function. No manual dark: classes needed.

Variant
Size
Type
<Accordion>
  <AccordionItem value="item-1" title="Section One">
    Content for the first section.
  </AccordionItem>
  <AccordionItem value="item-2" title="Section Two">
    Content for the second section.
  </AccordionItem>
  <AccordionItem value="item-3" title="Section Three">
    Content for the third section.
  </AccordionItem>
</Accordion>

01 Examples

FAQ Section

A realistic FAQ layout with rich content — the canonical real-world use case for Accordion.

Frequently Asked Questions

Everything you need to know to get started.

Basic Svelte knowledge helps, but our components are designed with simple, declarative APIs. If you can write HTML and pass props, you're good to go. Check the Getting Started guide for a gentle introduction.

We use a 3-layer token system: foundation, semantic, and interaction tokens. Dark mode is handled automatically via light-dark() — no manual dark: classes needed.

Absolutely. Every component is tree-shakeable. Import only what you need and your bundle stays lean.

Yes. All components follow WAI-ARIA patterns, support keyboard navigation, and include proper focus management. We test with screen readers and respect prefers-reduced-motion.

<div
  class="bg-surface-elevated border-border-subtle w-full overflow-hidden rounded-2xl border"
>
  <div class="border-border-subtle border-b px-6 py-4">
    <h3 class="text-text-primary font-semibold">Frequently Asked Questions</h3>
    <p class="text-text-tertiary mt-0.5 text-sm">
      Everything you need to know to get started.
    </p>
  </div>
  <div class="px-6 py-2">
    <Accordion defaultValue="faq-1">
      <AccordionItem value="faq-1" title="Do I need to know Svelte to use this?">
        <p class="text-text-secondary text-sm leading-relaxed">
          Basic Svelte knowledge helps, but our components are designed with simple,
          declarative APIs. If you can write HTML and pass props, you're good to go. Check the <a
            href={resolve('/getting-started')}
            class="text-primary underline">Getting Started guide</a
          > for a gentle introduction.
        </p>
      </AccordionItem>
      <AccordionItem value="faq-2" title="How does dark mode work?">
        <p class="text-text-secondary text-sm leading-relaxed">
          We use a 3-layer token system: foundation, semantic, and interaction tokens. Dark
          mode is handled automatically via <code
            class="bg-surface-base rounded px-1.5 py-0.5 text-xs">light-dark()</code
          >
          — no manual <code class="bg-surface-base rounded px-1.5 py-0.5 text-xs">dark:</code> classes
          needed.
        </p>
      </AccordionItem>
      <AccordionItem value="faq-3" title="Can I use only some components?">
        <p class="text-text-secondary text-sm leading-relaxed">
          Absolutely. Every component is tree-shakeable. Import only what you need and your
          bundle stays lean.
        </p>
      </AccordionItem>
      <AccordionItem value="faq-4" title="Is it accessible?">
        <p class="text-text-secondary text-sm leading-relaxed">
          Yes. All components follow WAI-ARIA patterns, support keyboard navigation, and
          include proper focus management. We test with screen readers and respect <code
            class="bg-surface-base rounded px-1.5 py-0.5 text-xs">prefers-reduced-motion</code
          >.
        </p>
      </AccordionItem>
    </Accordion>
  </div>
</div>

Controlled State

Bind the open item via bind:value for external state management — useful when the accordion's selection drives other UI.
Open: what-is
A Svelte 5 component library with built-in i18n, semantic design tokens, and zero-config dark mode.
Yes — Urbicon UI is free and open-source under the MIT license.
Check the documentation, open a GitHub issue, or join the community Discord.
<div class="flex w-full flex-col gap-4">
  <div class="flex items-center gap-2">
    <span class="text-text-tertiary text-xs font-medium">Open:</span>
    <Badge size="xs" intent="primary" variant="soft">{faqValue || '(none)'}</Badge>
  </div>
  <Accordion variant="card" bind:value={faqValue}>
    <AccordionItem value="what-is" title="What is Urbicon UI?">
      A Svelte 5 component library with built-in i18n, semantic design tokens, and zero-config
      dark mode.
    </AccordionItem>
    <AccordionItem value="pricing" title="Is it free?">
      Yes — Urbicon UI is free and open-source under the MIT license.
    </AccordionItem>
    <AccordionItem value="support" title="Where do I get help?">
      Check the documentation, open a GitHub issue, or join the community Discord.
    </AccordionItem>
  </Accordion>
</div>

Custom Trigger

Replace the default trigger with a custom snippet for full control over the header layout — icons, badges, multi-line metadata.

Includes community support, basic components, and public repos only.

Priority support, private repos, advanced theming, and early access to new components.

<Accordion variant="card" defaultValue="pro">
  <AccordionItem value="free">
    {#snippet trigger({ open: _open })}
      <div class="flex w-full items-center gap-3">
        <div
          class="bg-surface-hover rounded-modify flex size-8 items-center justify-center text-sm"
        >
          🆓
        </div>
        <div class="flex-1 text-left">
          <p class="text-text-primary text-sm font-semibold">Free Plan</p>
          <p class="text-text-tertiary text-xs">Up to 3 projects</p>
        </div>
        <Badge size="xs" intent="neutral" variant="soft">$0/mo</Badge>
      </div>
    {/snippet}
    <p class="text-text-secondary text-sm">
      Includes community support, basic components, and public repos only.
    </p>
  </AccordionItem>
  <AccordionItem value="pro">
    {#snippet trigger({ open: _open })}
      <div class="flex w-full items-center gap-3">
        <div
          class="bg-primary/10 text-primary rounded-modify flex size-8 items-center justify-center"
        >
          <ZapIcon size={16} />
        </div>
        <div class="flex-1 text-left">
          <p class="text-text-primary text-sm font-semibold">Pro Plan</p>
          <p class="text-text-tertiary text-xs">Unlimited projects</p>
        </div>
        <Badge size="xs" intent="primary" variant="filled">$29/mo</Badge>
      </div>
    {/snippet}
    <p class="text-text-secondary text-sm">
      Priority support, private repos, advanced theming, and early access to new components.
    </p>
  </AccordionItem>
</Accordion>

02 Built on Collapsible

Accordion vs Collapsible

Accordion coordinates multiple panels via a shared context. For a single expand/collapse panel, use Collapsible directly.

Single panel → Collapsible

Use Collapsible when you need a single panel that manages its own state. No context, no coordination — just expand and collapse.

Multi-panel → Accordion

Opening this closes panel B. Accordion coordinates multiple Collapsible panels via a shared context.
Single-mode, multiple-mode, non-collapsible — all managed by the Accordion wrapper.
<div class="flex w-full max-w-lg flex-col gap-2.5">
  <p class="text-text-tertiary text-xs font-medium tracking-wider uppercase">
    Single panel → Collapsible
  </p>
  <Collapsible variant="card" title="Standalone expand/collapse" defaultOpen>
    <p class="text-text-secondary text-sm">
      Use <code class="bg-surface-base rounded px-1.5 py-0.5 text-xs">Collapsible</code> when you
      need a single panel that manages its own state. No context, no coordination — just expand
      and collapse.
    </p>
  </Collapsible>
</div>
<div class="flex w-full max-w-lg flex-col gap-2.5">
  <p class="text-text-tertiary text-xs font-medium tracking-wider uppercase">
    Multi-panel → Accordion
  </p>
  <Accordion variant="card" defaultValue="a1">
    <AccordionItem value="a1" title="Coordinated panel A">
      Opening this closes panel B. Accordion coordinates multiple Collapsible panels via a
      shared context.
    </AccordionItem>
    <AccordionItem value="a2" title="Coordinated panel B">
      Single-mode, multiple-mode, non-collapsible — all managed by the Accordion wrapper.
    </AccordionItem>
  </Accordion>
</div>

Architecture note: Each AccordionItem uses Collapsible internally for its expand/collapse animation and ARIA attributes. The Accordion component adds multi-item coordination (single/multiple mode, non-collapsible, disabled) on top. See the Collapsible docs for the standalone API.

03 Customization

slotClasses Override

Restyle individual slots with overrides that win the cascade — wider border in primary, tinted background, bold primary-colored trigger text, and an inset content rail.
Every slot is overridable: the item gets a two-pixel primary border + tinted background, the trigger inherits the primary intent in bold, the chevron matches, and the content inner pane adds a primary left rail for emphasis.
slotClasses are applied to every item in the accordion, keeping the visual language consistent across sections.
<Accordion
  variant="card"
  defaultValue="styled"
  slotClasses={{
    item: 'border-2 border-primary/40 rounded-2xl bg-primary/5',
    trigger: 'text-primary font-bold',
    chevron: 'text-primary',
    contentInner: 'text-text-primary border-l-2 border-primary/40 pl-4'
  }}
>
  <AccordionItem value="styled" title="Restyled via slotClasses">
    Every slot is overridable: the item gets a two-pixel primary border + tinted background,
    the trigger inherits the primary intent in bold, the chevron matches, and the content
    inner pane adds a primary left rail for emphasis.
  </AccordionItem>
  <AccordionItem value="another" title="Consistent overrides">
    slotClasses are applied to every item in the accordion, keeping the visual language
    consistent across sections.
  </AccordionItem>
</Accordion>

Glassmorphism (unstyled)

Fully custom frosted-glass accordion built entirely with class overrides.
The accordion strips all defaults in unstyled mode. Every visual detail — background, blur, text color, spacing — is hand-crafted through class props.
A single backdrop-blur layer on the item wraps both trigger and content — no seams, no double-blur where the two panes meet.
Proof that unstyled gives full creative freedom while keeping structure, animation, and accessibility intact.
<Accordion unstyled defaultValue="glass-1" class="flex w-full flex-col gap-3">
  <AccordionItem
    unstyled
    value="glass-1"
    title="Frosted Glass Header"
    class="overflow-hidden rounded-xl border border-white/20 bg-white/10 backdrop-blur-md transition-colors hover:bg-white/15"
    slotClasses={{
      trigger:
        'flex w-full items-center justify-between px-5 py-3.5 text-sm font-medium text-white',
      chevron: 'size-4 text-white/60 transition-transform duration-200',
      contentInner: 'px-5 pb-4 pt-1 text-sm text-white/80'
    }}
  >
    The accordion strips all defaults in unstyled mode. Every visual detail — background,
    blur, text color, spacing — is hand-crafted through class props.
  </AccordionItem>
  <AccordionItem
    unstyled
    value="glass-2"
    title="Layered Transparency"
    class="overflow-hidden rounded-xl border border-white/20 bg-white/10 backdrop-blur-md transition-colors hover:bg-white/15"
    slotClasses={{
      trigger:
        'flex w-full items-center justify-between px-5 py-3.5 text-sm font-medium text-white',
      chevron: 'size-4 text-white/60 transition-transform duration-200',
      contentInner: 'px-5 pb-4 pt-1 text-sm text-white/80'
    }}
  >
    A single backdrop-blur layer on the item wraps both trigger and content — no seams, no
    double-blur where the two panes meet.
  </AccordionItem>
  <AccordionItem
    unstyled
    value="glass-3"
    title="Creative Freedom"
    class="overflow-hidden rounded-xl border border-white/20 bg-white/10 backdrop-blur-md transition-colors hover:bg-white/15"
    slotClasses={{
      trigger:
        'flex w-full items-center justify-between px-5 py-3.5 text-sm font-medium text-white',
      chevron: 'size-4 text-white/60 transition-transform duration-200',
      contentInner: 'px-5 pb-4 pt-1 text-sm text-white/80'
    }}
  >
    Proof that <code class="rounded bg-white/15 px-1.5 py-0.5">unstyled</code> gives full creative
    freedom while keeping structure, animation, and accessibility intact.
  </AccordionItem>
</Accordion>

Terminal (unstyled)

Monospace hacker aesthetic built entirely with class overrides.

NODE_ENV=production

PORT=3000

LOG_LEVEL=info

Process exited with code 0

● app.service - Application Server

  Active: active (running)

  Memory: 128.4M

[12:34:01] GET /api/health 200 2ms

[12:34:03] POST /api/users 201 45ms

[12:34:05] Listening on :3000

<Accordion
  unstyled
  defaultValue="term-1"
  class="w-full divide-y divide-emerald-500/20 font-mono"
>
  <AccordionItem
    unstyled
    value="term-1"
    title="$ cat /etc/config"
    slotClasses={{
      trigger:
        'flex w-full items-center justify-between py-3 text-xs text-emerald-300 transition-colors hover:text-emerald-400',
      chevron: 'size-3.5 text-emerald-400 transition-transform duration-200',
      contentInner: 'pb-3 text-xs leading-relaxed text-emerald-200'
    }}
  >
    <p>NODE_ENV=production</p>
    <p>PORT=3000</p>
    <p>LOG_LEVEL=info</p>
    <p class="mt-2 text-emerald-300">Process exited with code 0</p>
  </AccordionItem>
  <AccordionItem
    unstyled
    value="term-2"
    title="$ systemctl status app"
    slotClasses={{
      trigger:
        'flex w-full items-center justify-between py-3 text-xs text-emerald-300 transition-colors hover:text-emerald-400',
      chevron: 'size-3.5 text-emerald-400 transition-transform duration-200',
      contentInner: 'pb-3 text-xs leading-relaxed text-emerald-200'
    }}
  >
    <p class="text-emerald-400">● app.service - Application Server</p>
    <p class="text-emerald-400">
      &nbsp;&nbsp;Active: <span class="text-emerald-300">active (running)</span>
    </p>
    <p class="text-emerald-400">&nbsp;&nbsp;Memory: 128.4M</p>
  </AccordionItem>
  <AccordionItem
    unstyled
    value="term-3"
    title="$ tail -f /var/log/app.log"
    slotClasses={{
      trigger:
        'flex w-full items-center justify-between py-3 text-xs text-emerald-300 transition-colors hover:text-emerald-400',
      chevron: 'size-3.5 text-emerald-400 transition-transform duration-200',
      contentInner: 'pb-3 text-xs leading-relaxed text-emerald-200'
    }}
  >
    <p class="text-emerald-400">[12:34:01] GET /api/health 200 2ms</p>
    <p class="text-emerald-400">[12:34:03] POST /api/users 201 45ms</p>
    <p class="text-emerald-300">[12:34:05] Listening on :3000</p>
  </AccordionItem>
</Accordion>

The frosted-glass and terminal treatments above are preset material: register the slotClasses combination once under presets.Accordion / presets.AccordionItem on BlocksProvider and opt in per instance via preset — see Customization.

04 Accessibility

Built-in ARIA

Each trigger uses aria-expanded and aria-controls to link to its content panel. Content panels have role="region" with aria-labelledby pointing back to the trigger. The data-state attribute exposes open / closed for CSS-only styling.

Keyboard Navigation

Tab moves focus between triggers. Enter / Space toggle the focused item. Focus rings use focus-visible: so they only appear on keyboard navigation, never on mouse clicks.

Disabled State

Disabled triggers get the native disabled attribute, removing them from the tab order and preventing activation. Visual feedback via opacity-50 and cursor-not-allowed.

Reduced Motion

The expand/collapse animation uses CSS grid-template-rows transitions. When prefers-reduced-motion is enabled, transition durations are reduced via the design token system.

05 API Reference

17 props
17 props 1 required
Prop
Type
Default
Description

06 Types

Local type definitions used by this component.

5 types
Name
Kind
Category
Used by
Description

07 Installation

Import

import { Accordion, AccordionItem } from '@urbicon-ui/blocks';