Skip to content

Collapse

The Collapse component displays content in collapsible sections. Each section can be independently opened or closed. It supports full keyboard navigation, custom slots for headers and panels, and a multi-open configuration.

Usage Examples

Basic Usage

Simple collapsible sections

vue
<template>
  <SuCollapse :items="items" />
</template>

<script setup lang="ts">
const items = [
  { id: 'a', title: 'Section 1', content: 'Content of the first section.' },
  { id: 'b', title: 'Section 2', content: 'Content of the second section.' },
  { id: 'c', title: 'Section 3', content: 'Content of the third section.' },
]
</script>

Multiple Open

By default, opening a section closes the previous one. Enable multiple to allow several sections to be open at the same time.

vue
<template>
  <SuCollapse :items="items" multiple />
</template>

<script setup lang="ts">
const items = [
  { id: 'a', title: 'Item 1', content: 'Content for item 1.' },
  { id: 'b', title: 'Item 2', content: 'Content for item 2.' },
  { id: 'c', title: 'Item 3', content: 'Content for item 3.' },
]
</script>

Disabled Section

Add disabled: true to an item to make it non-interactive.

vue
<template>
  <SuCollapse :items="items" />
</template>

<script setup lang="ts">
const items = [
  { id: 'a', title: 'Active section', content: 'Accessible content.' },
  { id: 'b', title: 'Disabled section', content: 'Not accessible.', disabled: true },
  { id: 'c', title: 'Another active section', content: 'Accessible content.' },
]
</script>

Custom Header with Slot

The #header slot allows you to customise the content of each header - icons, badges, advanced formatting.

vue
<template>
  <SuCollapse :items="items">
    <template #header="{ item }">
      <div style="display: flex; align-items: center; gap: 8px; flex-grow: 1;">
        <component v-if="item.icon" :is="item.icon" style="width: 16px; height: 16px;" />
        <span>{{ item.title }}</span>
        <SuBadge v-if="item.badge" type="info">{{ item.badge }}</SuBadge>
      </div>
    </template>
  </SuCollapse>
</template>

<script setup lang="ts">
import { AtSymbolIcon, UserIcon, MagnifyingGlassIcon } from '@heroicons/vue/24/outline'

const items = [
  { id: 'a', title: 'Email', content: 'Email content.', icon: AtSymbolIcon },
  { id: 'b', title: 'Profile', content: 'Profile content.', icon: UserIcon, badge: 5 },
  { id: 'c', title: 'Search', content: 'Search content.', icon: MagnifyingGlassIcon },
]
</script>

Custom Panel with Slot

The #panel slot replaces the default rendering of each section's content.

vue
<template>
  <SuCollapse :items="items" multiple>
    <template #panel="{ item }">
      <article style="padding: 1rem;">
        <h3>{{ item.title }}</h3>
        <p>{{ item.content }}</p>
        <SuButton size="sm">Learn more</SuButton>
      </article>
    </template>
  </SuCollapse>
</template>

<script setup lang="ts">
const items = [
  { id: 'a', title: 'Vue 3', content: 'Progressive JavaScript framework.' },
  { id: 'b', title: 'TypeScript', content: 'Typed superset of JavaScript.' },
]
</script>

RTL Support

vue
<template>
  <div dir="rtl">
    <SuCollapse :items="items" />
  </div>
</template>

<script setup lang="ts">
const items = [
  { id: 'a', title: 'القسم 1', content: 'محتوى القسم الأول' },
  { id: 'b', title: 'القسم 2', content: 'محتوى القسم الثاني' },
]
</script>

API

Props

PropTypeDefaultDescription
itemsCollapseItem[][]List of sections to display
multiplebooleanfalseIf true, multiple sections can be open at the same time

CollapseItem Interface

typescript
interface CollapseItem {
  id?: string       // Unique identifier (auto-generated if absent)
  title: string     // Title displayed in the header
  content: string   // Default text content (used without #panel slot)
  icon?: Component  // Icon component (e.g. HeroIcon) -  use via the #header slot
  badge?: number    // Badge value -  use via the #header slot
  disabled?: boolean // If true, the section is non-interactive
}

Slots

SlotExposed propsDescription
#header{ item: CollapseItem, index: number }Replaces the header content of each section
#panel{ item: CollapseItem, index: number }Replaces the panel content of each section
default-Displayed when items is empty or not provided

Keyboard Navigation

KeyAction
Enter / SpaceOpens or closes the focused section
ArrowDownMoves focus to the next header
ArrowUpMoves focus to the previous header
HomeMoves focus to the first header
EndMoves focus to the last header

Accessibility

The Collapse component complies with WCAG 2.1 Level AA standards and follows the WAI-ARIA Accordion pattern.

  • Semantic structure: each section is wrapped in an <h3> + <button> for a correct heading hierarchy and efficient screen reader navigation.
  • aria-expanded: indicates the open/closed state of each section to screen readers.
  • aria-controls: links the header button to its content panel.
  • aria-labelledby: links the panel back to its header button.
  • Disabled section: the native disabled attribute on the button is recognised by assistive technologies.
  • Full keyboard navigation: all keys from the ARIA Accordion pattern are implemented (see table above).
  • Visible focus: focusable elements display an outline that meets accessibility standards.
  • High contrast mode: the component automatically adapts in high contrast environments.
  • RTL support: the chevron automatically mirrors in right-to-left writing mode.

Publié sous licence MIT.