🌟 Introduction
Ce composant permet de gérer un ensemble de cases à cocher DSFR. Il est composé d'un libellé (legend
), d'options individuelles représentées par le composant DsfrCheckbox
, et d'un message d'information, d'erreur ou de validation global.
📐 Structure
Le composant DsfrCheckboxSet
est composé des éléments suivants :
- Un élément
<fieldset>
contenant l'ensemble des cases à cocher - Une légende (
legend
) définie par la proplegend
et personnalisable avec le slotlegend
- Un groupe de cases à cocher individuelles rendues par le composant
DsfrCheckbox
- Un message d'information, d'erreur ou de validation, affiché en dessous du groupe de cases à cocher
🛠️ Props
Nom | Type | Description | Obligatoire |
---|---|---|---|
options | (DsfrCheckboxProps & InputHTMLAttributes)[] | Tableau d'options définissant les cases à cocher individuelles | ✅ |
modelValue | string[] | Valeur courante du composant, un tableau de valeurs (propriété value de chaque option de la prop options ) des cases cochées | ✅ |
disabled | boolean | Indique si l'ensemble des cases à cocher est désactivé | |
errorMessage | string | Message d'erreur global à afficher | |
inline | boolean | Affiche les cases à cocher en ligne (par défaut : false ) | |
legend | string | Texte de la légende | |
required | boolean | Indique si l'ensemble des cases à cocher est obligatoire | |
small | boolean | Affiche les cases à cocher en taille réduite | |
titleId | string | Identifiant unique du champ (générée automatiquement si non fournie) | |
validMessage | string | Message de validation global à afficher |
Attention
Avant la v7, le tableau modelValue
était un tableau de string
avec les valeurs des propriétés de l’attribut name
de chaque case à cocher.
Ce n’était ni une API idéale, ni le comportement attendu en Vue natif ou en HTML/JS natif.
📡 Événements
DsfrCheckboxSet
émet l'événement suivant :
Nom | Description |
---|---|
update:modelValue | Est émis lorsque la sélection des cases à cocher change |
🧩 Slots
DsfrCheckboxSet
fournit les slots suivants pour la personnalisation :
legend
: Permet de personnaliser le contenu de la légende.required-tip
: Permet d'ajouter plus qu’un astérisque pour indiquer que le champ est obligatoire ou d’autres détails sur cette case à cocher.
🪆 Relation avec DsfrCheckbox
DsfrChecboxSet
utilise en interne DsfrCheckbox
, et permet de récupérer dans modelValue
sous forme de tableau les valeurs de la prop value
de chaque case à cocher qui est cochée.
Cf. les exemples ci-dessous
📝 Exemples
<script lang="ts" setup>
import { ref } from 'vue'
import DsfrCheckboxSet from '../DsfrCheckboxSet.vue'
const modelValue1 = ref([])
const modelValue2 = ref([])
const modelValue3 = ref([])
const modelValue4 = ref([])
const modelValue5 = ref([])
const modelValue6 = ref([])
const options1 = [
{
label: 'Première valeur',
value: 'une chaîne en premier',
id: 'name1-1',
name: 'name1-1',
hint: 'La première valeur est une chaîne de caractères',
},
{
label: 'Deuxième valeur',
value: 42,
id: 'name1-2',
name: 'name1-2',
hint: 'La valeur est ici un chiffre',
},
{
label: 'Troisième valeur',
value: { foo: 'foo', bar: 42 },
id: 'name1-3',
name: 'name1-3',
hint: 'Et ici la valeur est un littéral objet',
},
]
const options2 = structuredClone(options1).map(option => Object.fromEntries(
Object.entries(option).map(([key, value]) => [key, ['id', 'name'].includes(key) ? value.replace('name1', 'name2') : value]),
))
const options3 = structuredClone(options1).map(option => Object.fromEntries(
Object.entries(option).map(([key, value]) => [key, ['id', 'name'].includes(key) ? value.replace('name1', 'name3') : value]),
))
const options4 = structuredClone(options1).map(option => Object.fromEntries(
Object.entries(option).filter(([key]) => key !== 'hint').map(([key, value]) => [key, ['id', 'name'].includes(key) ? value.replace('name1', 'name4') : value]),
))
const options5 = structuredClone(options1).map(option => Object.fromEntries(
Object.entries(option).filter(([key]) => key !== 'hint').map(([key, value]) => [key, ['id', 'name'].includes(key) ? value.replace('name1', 'name5') : value]),
))
const options6 = structuredClone(options1).map(option => Object.fromEntries(
Object.entries(option).filter(([key]) => key !== 'hint').map(([key, value]) => [key, ['id', 'name'].includes(key) ? value.replace('name1', 'name6') : value]),
))
const errorMessage = 'Message d’erreur'
const validMessage = 'Message de validation'
</script>
<template>
<div class="fr-container fr-my-2v">
<div class="fr-my-2v">
<DsfrCheckboxSet
v-model="modelValue1"
legend="Groupe de cases à cocher simple"
:options="options1"
/>
<p>
modelValue1: {{ modelValue1 }}
</p>
</div>
<div class="fr-my-2v">
<DsfrCheckboxSet
v-model="modelValue2"
legend="Groupe de cases à cocher avec erreur"
:options="options2"
:error-message="errorMessage"
/>
<p>
modelValue2: {{ modelValue2 }}
</p>
</div>
<div class="fr-my-2v">
<DsfrCheckboxSet
v-model="modelValue3"
legend="Groupe de cases à cocher avec message de validation"
:options="options3"
:valid-message="validMessage"
/>
<p>
modelValue3: {{ modelValue3 }}
</p>
</div>
<div class="fr-my-2v">
<DsfrCheckboxSet
v-model="modelValue4"
legend="Groupe de cases à cocher en ligne"
:options="options4"
inline
/>
<p>
modelValue4: {{ modelValue4 }}
</p>
</div>
<div class="fr-my-2v">
<DsfrCheckboxSet
v-model="modelValue5"
legend="Groupe de cases à cocher en ligne avec erreur"
:options="options5"
inline
error-message="Message d’erreur"
/>
<p>
modelValue5: {{ modelValue5 }}
</p>
</div>
<div class="fr-my-2v">
<DsfrCheckboxSet
v-model="modelValue6"
legend="Groupe de cases à cocher en ligne avec erreur"
:options="options6"
inline
valid-message="Message de validation"
/>
<p>
modelValue6: {{ modelValue6 }}
</p>
</div>
</div>
</template>
⚙️ Code source du composant
<script lang="ts">
import { computed } from 'vue'
import { getRandomId } from '../../utils/random-utils'
import DsfrCheckbox from './DsfrCheckbox.vue'
import type { DsfrCheckboxSetProps } from './DsfrCheckbox.types'
export type { DsfrCheckboxSetProps }
</script>
<script lang="ts" setup>
const props = withDefaults(defineProps<DsfrCheckboxSetProps>(), {
titleId: () => getRandomId('checkbox', 'group'),
errorMessage: '',
validMessage: '',
legend: '',
options: () => [],
modelValue: () => [],
})
const message = computed(() => {
return props.errorMessage || props.validMessage
})
const additionalMessageClass = computed(() => {
return props.errorMessage ? 'fr-error-text' : 'fr-valid-text'
})
const ariaLabelledby = computed(() => message.value ? `${props.titleId} messages-${props.titleId}` : props.titleId)
const modelValue = defineModel()
</script>
<template>
<div class="fr-form-group">
<fieldset
class="fr-fieldset"
:class="{
'fr-fieldset--error': errorMessage,
'fr-fieldset--valid': !errorMessage && validMessage,
}"
:disabled="disabled"
:aria-labelledby="ariaLabelledby"
:aria-invalid="ariaInvalid"
:role="(errorMessage || validMessage) ? 'group' : undefined"
>
<legend
:id="titleId"
class="fr-fieldset__legend fr-text--regular"
>
<!-- @slot Slot pour personnaliser tout le contenu de la balise <legend> cf. [DsfrInput](/?path=/story/composants-champ-de-saisie-champ-simple-dsfrinput--champ-avec-label-personnalise). Une **rte le même nom pour une légende simple** (texte sans mise en forme) -->
<slot name="legend">
{{ legend }}
<!-- @slot Slot pour indiquer que le champ est obligatoire. Par défaut, met une astérisque si `required` est à true (dans un `<span class="required">`) -->
<slot name="required-tip">
<span
v-if="required"
class="required"
> *</span>
</slot>
</slot>
</legend>
<slot>
<DsfrCheckbox
v-for="option in options"
:id="option.id"
:key="option.id || option.name"
v-model="modelValue"
:value="option.value"
:name="option.name"
:label="option.label"
:disabled="option.disabled"
:aria-disabled="option.disabled"
:small="small"
:inline="inline"
:hint="option.hint"
/>
</slot>
<div
v-if="message"
:id="`messages-${titleId}`"
class="fr-messages-group"
role="alert"
>
<p
class="fr-message--info flex items-center"
:class="additionalMessageClass"
>
<span>{{ message }}</span>
</p>
</div>
</fieldset>
</div>
</template>
import type { InputHTMLAttributes } from 'vue'
export type DsfrCheckboxProps = {
id?: string
name: string
required?: boolean
value: unknown
checked?: boolean
modelValue: Array<unknown>
small?: boolean
inline?: boolean
label?: string
errorMessage?: string
validMessage?: string
hint?: string
}
export type DsfrCheckboxSetProps = {
titleId?: string
disabled?: boolean
inline?: boolean
required?: boolean
small?: boolean
errorMessage?: string
validMessage?: string
legend?: string
options?: (DsfrCheckboxProps & InputHTMLAttributes)[]
modelValue?: Array<unknown>
ariaInvalid?: boolean
}