Components

Accordion

A set of collapsible sections with headings.

A vertically stacked list of items that can be expanded or collapsed. Supports single or multiple open items and full keyboard navigation.

Anatomy

Accordion is a single component. You shape every part through named slots:

  • #trigger — content rendered inside the trigger button (defaults to the item label)
  • #icon — optional chevron/indicator rendered after the trigger content
  • #content — the panel body revealed when the item is open
  • #[item.slot] — per-item override when an item has a slot key

The trigger button itself is rendered by the component; use the ui.trigger prop to add classes to it.

Usage

A headless Vue component library with a Vue-native slots API. Zero default styles.

No — bring your own CSS, Tailwind, or any design system. Full control over every pixel.

Yes, fully WAI-ARIA compliant with keyboard navigation and screen reader support built in.

Examples

Custom trigger and icon

The #trigger slot is rendered inside the trigger button — use it to customise the label content. Style the button itself with ui.trigger. Use #icon to override the chevron indicator.

<template>
  <Accordion :items="items" :ui="{ trigger: 'px-4 py-3 hover:bg-neutral-50' }">
    <template #trigger="{ item, isOpen }">
      <span :class="['trigger-label', { 'trigger-label--open': isOpen }]">
        {{ item.label }}
      </span>
    </template>

    <template #icon="{ isOpen }">
      <svg :class="['icon', { 'icon--open': isOpen }]" .../>
    </template>
  </Accordion>
</template>

Multiple open items

<template>
  <Accordion :items="items" type="multiple" />
</template>

Per-item custom content

Give an item a slot key to render rich content in its panel.

<script setup lang="ts">
const items = [
  { value: "form", label: "Contact us", slot: "contact-form" },
];
</script>

<template>
  <Accordion :items="items">
    <template #contact-form="{ close }">
      <form @submit.prevent="close">
        <input type="email" placeholder="your@email.com" />
        <button type="submit">Send</button>
      </form>
    </template>
  </Accordion>
</template>

API Reference

Props

PropTypeDefaultDescription
itemsAccordionItem[]Required. List of accordion items.
type"single" | "multiple""single"Whether one or many items can be open simultaneously.
collapsiblebooleanfalseAllow toggling the open item closed again (single mode only).
disabledbooleanfalseDisable all items.
orientation"vertical" | "horizontal""vertical"Orientation of the accordion.
unmountOnHidebooleanfalseRemove content from the DOM when closed instead of hiding it.
valueKeystringProperty to read as the unique item value.
labelKeystring"label"Property to use as the trigger label.
contentKeystringProperty to use as the body text.
disabledKeystring"disabled"Property to read for per-item disabled state.
asstring"div"Root element tag.
uiAccordionUiCSS class overrides.

AccordionItem

KeyTypeDescription
valuestringUnique identifier. Auto-generated if omitted.
labelstringTrigger label text.
contentstringPanel body text (used when no content slot is provided).
disabledbooleanDisables this item.
slotstringNamed slot key for a custom panel content slot.

Slots

SlotScoped propsDescription
trigger{ item, value, isOpen, toggle }Trigger button content for every item.
icon{ isOpen, item }Icon inside the trigger (e.g. chevron).
content{ item, value, isOpen }Panel body content for every item.
[item.slot]{ item, value, isOpen }Per-item panel override when item.slot is set.

Emits

EventPayloadDescription
value-change[value: string | string[], details]Fired when the open item(s) change.

UI Options

KeyDescription
itemWrapper element around each trigger + content pair.
triggerThe trigger button element.
iconThe icon container inside the trigger.
contentThe panel content element.