Skip to content

🌟 Introduction

Les cases à cocher permettent à l’utilisateur de sélectionner une ou plusieurs options dans une liste. Elles sont utilisées pour effectuer des sélections multiples (de 0 à N éléments) ou bien pour permettre un choix binaire, lorsque l’utilisateur peut sélectionner ou désélectionner une seule option.

La case à cocher peut être utilisée seule ou en liste. Évitez les listes de plus de 5 items et lorsque vous souhaitez contraindre le choix à un seul élément - utiliser les boutons radios.

🏅 La documentation sur les cases à cocher sur le DSFR

La story sur les cases à cocher sur le storybook de VueDsfr

📐 Structure

Le composant DsfrCheckbox est composé des éléments suivants :

  • Une case à cocher <input type="checkbox">
  • Un label associé à la case à cocher, défini par la prop label et personnalisable avec le slot label
  • Un message d'information, d'erreur (prop errorMessage) ou de validation (prop validMessage), affiché en dessous de la case à cocher

🛠️ Props

NomTypeDéfautObligatoireDescription
namestringNom du champ <input>
modelValuebooleanValeur booléenne associée à la case à cocher
labelstringTexte du label associé à la case à cocher
errorMessagestring''Message d'erreur à afficher en dessous de la case à cocher
hintstring''Texte d'information complémentaire affiché en dessous de la case à cocher
idstringchaîne pseudo-aléatoireIdentifiant unique du composant (générée automatiquement si non fournie)
inlineboolean''Affiche la case à cocher en ligne (par défaut : false)
requiredboolean''Indique si la case à cocher est obligatoire (par défaut : false)
smallboolean''Affiche la case à cocher en taille réduite (par défaut : false)
validMessagestring''Message de validation à afficher en dessous de la case à cocher

📡 Événements

DsfrCheckbox émet l'événement suivant :

NomtypeDescription
update:modelValuebooleanEst émis lorsque la valeur de la case à cocher change

🧩 Slots

DsfrCheckbox fournit les slots suivants pour la personnalisation :

  • label : Permet de personnaliser le contenu complet du label associé à la case à cocher.
  • required-tip : Permet d'ajouter un astérisque indiquant que le champ est obligatoire.

📝 Exemples

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

import DsfrCheckbox from '../DsfrCheckbox.vue'

const hint = 'Indication pour ce champ'
const modelValue = ref(undefined)

const errorMessage = 'Message d’erreur'
const validMessage = 'Message de validation'
</script>

<template>
  <div class="fr-container fr-my-2v">
    <DsfrCheckbox
      v-model="modelValue"
      name="checkbox-simple"
      label="Case à cocher simple"
    />
    {{ modelValue }}

    <DsfrCheckbox
      v-model="modelValue"
      name="checkbox-disabled"
      label="Case à cocher désactivée"
      disabled
    />

    <DsfrCheckbox
      v-model="modelValue"
      name="checkbox-hint"
      label="Case à cocher avec indication"
      :hint="hint"
    />

    <DsfrCheckbox
      v-model="modelValue"
      label="Case à cocher obligatoire"
      required
      :hint="hint"
    />

    <DsfrCheckbox
      v-model="modelValue"
      name="checkbox-required-custom"
      label="Case à cocher obligatoire personnalisée"
      required
      :hint="hint"
    >
      <template #required-tip>
        <em class="required">&nbsp;(obligatoire)</em>
      </template>
    </DsfrCheckbox>

    <DsfrCheckbox
      v-model="modelValue"
      name="checkbox-error"
      label="Case à cocher avec message d’erreur"
      required
      :hint="hint"
      :error-message="errorMessage"
    />

    <DsfrCheckbox
      v-model="modelValue"
      name="checkbox-error"
      label="Case à cocher avec message de validation"
      required
      :hint="hint"
      :valid-message="validMessage"
    />
  </div>
</template>

<style scoped>
.required {
  color: #f60700;
}
</style>

⚙️ Code source du composant

vue
<script lang="ts" setup>
import { computed } from 'vue'
import { getRandomId } from '../../utils/random-utils'

import type { DsfrCheckboxProps } from './DsfrCheckbox.types'

export type { DsfrCheckboxProps }

defineOptions({
  inheritAttrs: false,
})

const props = withDefaults(defineProps<DsfrCheckboxProps>(), {
  id: () => getRandomId('basic', 'checkbox'),
  hint: '',
  errorMessage: '',
  validMessage: '',
  label: '',
})

const emit = defineEmits<{ (event: 'update:modelValue', value: boolean): void }>()

const message = computed(() => props.errorMessage || props.validMessage)

const additionalMessageClass = computed(() => props.errorMessage ? 'fr-error-text' : 'fr-valid-text')

const emitNewValue = ($event: InputEvent) => {
  // @ts-expect-error This is a checkbox input event, so `checked` property is present
  emit('update:modelValue', $event.target.checked)
}
</script>

<template>
  <div
    class="fr-fieldset__element"
    :class="{ 'fr-fieldset__element--inline': inline }"
  >
    <div
      class="fr-checkbox-group"
      :class="{
        'fr-checkbox-group--error': errorMessage,
        'fr-checkbox-group--valid': !errorMessage && validMessage,
        'fr-checkbox-group--sm': small,
      }"
    >
      <input
        :id="id"
        :name="name"
        type="checkbox"
        :checked="modelValue"
        :required
        v-bind="$attrs"
        :data-testid="`input-checkbox-${id}`"
        :data-test="`input-checkbox-${id}`"
        @change="emitNewValue($event as InputEvent)"
      >
      <label
        :for="id"
        class="fr-label"
      >
        <!-- @slot Slot pour personnaliser tout le contenu de la balise <label> cf. [DsfrInput](/?path=/story/composants-champ-de-saisie-champ-simple-dsfrinput--champ-avec-label-personnalise). Une **props porte le même nom pour un label simple** (texte sans mise en forme) -->
        <slot name="label">
          {{ label }}
          <!-- @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"
            >&nbsp;*</span>
          </slot>
        </slot>

        <span
          v-if="hint"
          class="fr-hint-text"
        >
          {{ hint }}
        </span>
      </label>
      <div
        v-if="message"
        class="fr-messages-group"
        aria-live="assertive"
        role="alert"
      >
        <p
          class="fr-message--info  flex  items-center"
          :class="additionalMessageClass"
        >
          {{ message }}
        </p>
      </div>
    </div>
  </div>
</template>
ts
import type { InputHTMLAttributes } from 'vue'

export type DsfrCheckboxProps = {
  id?: string
  name: string
  required?: boolean
  modelValue?: boolean
  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?: string[]
  ariaInvalid?: boolean
}