Skip to content

Collapse ​

Le composant Collapse affiche du contenu en sections repliables. Chaque section peut être ouverte ou fermée indépendamment. Il supporte la navigation clavier complète, les slots personnalisés pour les en-têtes et panneaux, ainsi qu'une configuration multi-ouverture.

Exemples d'utilisation ​

Utilisation de base ​

Sections repliables simples

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

<script setup lang="ts">
const items = [
  { id: 'a', title: 'Section 1', content: 'Contenu de la première section.' },
  { id: 'b', title: 'Section 2', content: 'Contenu de la deuxième section.' },
  { id: 'c', title: 'Section 3', content: 'Contenu de la troisième section.' },
]
</script>

Ouverture multiple ​

Par défaut, l'ouverture d'une section ferme la précédente. Activez multiple pour permettre d'ouvrir plusieurs sections simultanément.

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

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

Section désactivée ​

Ajoutez disabled: true à un item pour le rendre non interactif.

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

<script setup lang="ts">
const items = [
  { id: 'a', title: 'Section active', content: 'Contenu accessible.' },
  { id: 'b', title: 'Section désactivée', content: 'Non accessible.', disabled: true },
  { id: 'c', title: 'Autre section active', content: 'Contenu accessible.' },
]
</script>

En-tête personnalisé avec slot ​

Le slot #header permet de personnaliser le contenu de chaque en-tête - icônes, badges, mise en forme avancée.

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: 'Contenu email.', icon: AtSymbolIcon },
  { id: 'b', title: 'Profil', content: 'Contenu profil.', icon: UserIcon, badge: 5 },
  { id: 'c', title: 'Recherche', content: 'Contenu recherche.', icon: MagnifyingGlassIcon },
]
</script>

Panneau personnalisé avec slot ​

Le slot #panel permet de remplacer le rendu par défaut du contenu de chaque section.

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

<script setup lang="ts">
const items = [
  { id: 'a', title: 'Vue 3', content: 'Framework JavaScript progressif.' },
  { id: 'b', title: 'TypeScript', content: 'Surcouche typée de JavaScript.' },
]
</script>

Support RTL ​

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 ​

PropTypeDéfautDescription
itemsCollapseItem[][]Liste des sections à afficher
multiplebooleanfalseSi true, plusieurs sections peuvent être ouvertes simultanément

Interface CollapseItem ​

typescript
interface CollapseItem {
  id?: string       // Identifiant unique (généré automatiquement si absent)
  title: string     // Titre affiché dans l'en-tête
  content: string   // Contenu textuel par défaut (utilisé sans slot #panel)
  icon?: Component  // Composant icône (ex. HeroIcon) -  à utiliser via le slot #header
  badge?: number    // Valeur de badge -  à utiliser via le slot #header
  disabled?: boolean // Si true, la section est non interactive
}

Slots ​

SlotProps exposéesDescription
#header{ item: CollapseItem, index: number }Remplace le contenu de l'en-tête de chaque section
#panel{ item: CollapseItem, index: number }Remplace le contenu du panneau de chaque section
default-Affiché si items est vide ou non fourni
ToucheAction
Enter / EspaceOuvre ou ferme la section focalisée
ArrowDownDéplace le focus vers l'en-tête suivant
ArrowUpDéplace le focus vers l'en-tête précédent
HomeDéplace le focus vers le premier en-tête
EndDéplace le focus vers le dernier en-tête

Accessibilité ​

Le composant Collapse est conforme aux normes WCAG 2.1 niveau AA et suit le pattern WAI-ARIA Accordion.

  • Structure sémantique : chaque section est encapsulée dans un <h3> + <button> pour une hiérarchie correcte et une navigation efficace au lecteur d'écran.
  • aria-expanded : indique l'état ouvert/fermé de chaque section au lecteur d'écran.
  • aria-controls : lie le bouton d'en-tête à son panneau de contenu.
  • aria-labelledby : lie le panneau à son bouton d'en-tête.
  • Section désactivée : l'attribut disabled sur le bouton est reconnu nativement par les technologies d'assistance.
  • Navigation clavier complète : toutes les touches du pattern ARIA Accordion sont implémentées (voir tableau ci-dessus).
  • Focus visible : les éléments focusables affichent un contour conforme aux standards d'accessibilité.
  • Mode contraste élevé : le composant s'adapte automatiquement en mode contraste élevé.
  • Support RTL : le chevron s'inverse automatiquement en mode écriture droite à gauche.

Publié sous licence MIT.