Skip to content

Groupe d’accordéons - DsfrAccordionsGroup

🌟 Introduction

Le composant DsfrAccordionsGroup permet de regrouper plusieurs accordéons en une seule unité cohérente. Il gère la logique de sélection active entre les accordéons enfants, permettant ainsi d'ouvrir un accordéon tout en fermant les autres. Ce composant est essentiel pour organiser des ensembles d'accordéons liés de manière interactive.

🏅 La documentation sur l’accordéon sur le DSFR

La story sur l’accordéon sur le storybook de VueDsfr

Le composant DsfrAccordionsGroup agit comme un conteneur pour les composants d'accordéons individuels. Il contrôle quel accordéon est actuellement ouvert, garantissant qu'un seul peut être déplié à la fois.

🛠️ Props

Nom de PropTypePar défautDescription
modelValuenumber-1Index de l'accordéon actuellement actif. Cette prop est utilisée pour le contrôle externe de l'accordéon ouvert (un seul peut être ouvert à la fois).

📡 Événements

Nom de l'ÉvénementPayloadDescription
update:modelValuenumberÉmis lorsque l'accordéon actif change. Le payload est l'index du nouvel accordéon ouvert.

Astuce

Il est donc possible (et recommandé) d’utiliser la directive v-model sur ce composant.

🧩 Slots

  • default : Slot par défaut pour le contenu du groupe d'accordéons. Ce slot contiendra les composants DsfrAccordion enfants.

📝 Exemple

vue
<script lang="ts" setup>
import { ref } from 'vue'

import DsfrAccordion from '../DsfrAccordion.vue'
import DsfrAccordionsGroup from '../DsfrAccordionsGroup.vue'

const title1 = ref('Un titre d’accordéon 1')
const title2 = ref('Un titre d’accordéon 2')
const title3 = ref('Un titre d’accordéon 3')

const activeAccordion = ref<number>()
</script>

<template>
  <DsfrAccordionsGroup v-model="activeAccordion">
    <DsfrAccordion
      id="accordion-1"
      :title="title1"
    >
      Contenu de l’accordéon 1
    </DsfrAccordion>
    <DsfrAccordion
      id="accordion-2"
      :title="title2"
    >
      Contenu de l’accordéon 2
    </DsfrAccordion>
    <DsfrAccordion
      id="accordion-3"
      :title="title3"
    >
      Contenu de l’accordéon 3
    </DsfrAccordion>
  </DsfrAccordionsGroup>
</template>

⚙️ Code source des composants

vue
<script setup lang="ts">
import { computed, onUnmounted, provide, ref, type Ref, watch } from 'vue'

import { registerAccordionKey } from './injection-key'

const props = withDefaults(defineProps<{
  modelValue?: number
}>(), {
  modelValue: -1,
})

const emit = defineEmits<{
  'update:modelValue': [value: number]
}>()

const activeAccordion = computed({
  get: () => props.modelValue,
  set (accordionId: number) {
    emit('update:modelValue', accordionId)
  },
})
const accordions = ref(new Map<number, string>())
const currentId = ref(0)
provide(registerAccordionKey, (title: Ref<string>) => {
  const myIndex = currentId.value++
  accordions.value.set(myIndex, title.value)

  const isActive = computed(() => myIndex === activeAccordion.value)

  watch(title, () => {
    accordions.value.set(myIndex, title.value)
  })

  function expand (): void {
    if (activeAccordion.value === myIndex) {
      activeAccordion.value = -1
      return
    }
    activeAccordion.value = myIndex
  }

  onUnmounted(() => {
    accordions.value.delete(myIndex)
  })

  return { isActive, expand }
})
</script>

<template>
  <div
    class="fr-accordions-group"
  >
    <!-- @slot Slot par défaut pour le contenu de la liste. Sera dans `<div class="fr-accordions-group">` -->
    <slot />
  </div>
</template>
ts
import type { TitleTag } from '@/common-types'

export type DsfrAccordionProps = {
  id?: string
  selected?: boolean
  title?: string
  titleTag?: TitleTag
}