Accordéon - DsfrAccordion
🌟 Introduction
Les accordéons permettent aux utilisateurs d'afficher et de masquer des sections de contenu présentés dans une page.
🏅 La documentation sur l’accordéon sur le DSFR
La story sur l’accordéon sur le storybook de VueDsfr📐 Structure
Un accordéon est constitué des éléments suivants :
- un en-tête (prop
title
, de typestring
), correspondant au titre de la section - obligatoire. - une icône, indique quand le panneau est fermé, quand le panneau est ouvert.
- un séparateur
- une zone de contenu, masquée par défaut pouvant contenir tout type d'élément, le
slot
par défaut est fait pour ça
Autres props :
id
: identifiant du contenu de l’accordéon, qui est utilisé aussi pour l’attributaria-controls
du bouton qui permet de plier et déplier l’accordéonexpandedId
: identifiant de l’accordéon actuellement déplié (pour savoir si l’accordéon doit être déplié)
🛠️ Props
Nom | Type | Défaut | Obligatoire |
---|---|---|---|
title | string | getRandomId('accordion') | ✅ |
titleTag | TitleTag | 'h3' | |
id | string | random string |
📡 Évenements
Pas d'événements spécifiques émis directement par ce composant.
🧩 Slots
title
: Slot pour le contenu personnalisé du titre de l’accordéon. Si non utilisé, le texte fourni via la proptitle
sera utilisé.default
: Slot pour le contenu principal de l'accordéon, affiché dans la section repliable.
Utilisation
Ce composant peut être utilisé uniquement avec DsfrAccordionsGroup
.
⚙️ Code source du composant
vue
<script lang="ts" setup>
import { inject, onMounted, ref, toRef, watch } from 'vue'
import { useCollapsable } from '../../composables'
import { getRandomId } from '../../utils/random-utils'
import { registerAccordionKey } from './injection-key'
import type { DsfrAccordionProps } from './DsfrAccordion.types'
export type { DsfrAccordionProps }
const props = withDefaults(
defineProps<DsfrAccordionProps>(),
{
id: () => getRandomId('accordion'),
title: 'Sans intitulé',
titleTag: 'h3',
},
)
const {
collapse,
collapsing,
cssExpanded,
doExpand,
onTransitionEnd,
} = useCollapsable()
const isStandaloneActive = ref()
const useAccordion = inject(registerAccordionKey)!
const { isActive, expand } = useAccordion?.(toRef(() => props.title)) ?? { isActive: isStandaloneActive, expand: () => isStandaloneActive.value = !isStandaloneActive.value }
onMounted(() => {
// Accordion can be expanded by default
// We need to trigger the expand animation on mounted
if (isActive.value) {
doExpand(true)
}
})
watch(isActive, (newValue, oldValue) => {
/*
* @see https://github.com/GouvernementFR/dsfr/blob/main/src/core/script/collapse/collapse.js
*/
if (newValue !== oldValue) {
doExpand(newValue)
}
})
</script>
<template>
<section class="fr-accordion">
<component
:is="titleTag"
class="fr-accordion__title"
>
<button
class="fr-accordion__btn"
:aria-expanded="isActive"
:aria-controls="id"
type="button"
@click="expand()"
>
<!-- @slot Slot pour le contenu personnalisé du titre de l’accordéon. Une **props du même nom est utilisable pour du texte simple** sans mise en forme. -->
<slot name="title">
{{ title }}
</slot>
</button>
</component>
<div
:id="id"
ref="collapse"
class="fr-collapse"
:class="{
'fr-collapse--expanded': cssExpanded, // Need to use a separate data to add/remove the class after a RAF
'fr-collapsing': collapsing,
}"
@transitionend="onTransitionEnd(isActive)"
>
<!-- @slot Slot par défaut pour le contenu de l’accordéon: sera dans `<div class="fr-collapse">` -->
<slot />
</div>
</section>
</template>
ts
import type { TitleTag } from '@/common-types'
export type DsfrAccordionProps = {
id?: string
selected?: boolean
title?: string
titleTag?: TitleTag
}
ts
import type { InjectionKey, Ref } from 'vue'
type RegisterTab = (title: Ref<string>) => {
isActive: Ref<boolean>
expand: () => void
}
export const registerAccordionKey: InjectionKey<RegisterTab> = Symbol('accordions')