Normes · ARIA

Rôle Widget

checkbox

Marque un élément comme case à cocher à deux ou trois états. Préférez <input type="checkbox"> ; n'utilisez role="checkbox" que si l'élément natif est impossible — par exemple pour un contrôle tri-état devant afficher une valeur mixte.

Quand l’utiliser

Utilisez <input type="checkbox">. L’élément natif fournit gratuitement le focus, l’activation par Espace, la pseudo-classe :checked, la soumission de formulaire et la propriété JS indeterminate pour le tri-état. role="checkbox" existe pour deux cas :

  • Vous avez besoin d’une case à cocher tri-état exposée comme aria-checked="mixed" (un « tout sélectionner » qui reflète l’état des enfants).
  • Un système de design livre un composant de case à cocher personnalisé que vous ne pouvez pas remplacer.

Si vous implémentez role="checkbox" sur un élément non-input, vous devez définir aria-checked (obligatoire), gérer tabindex="0" et gérer keydown pour Espace.

Contrat clavier + focus

Conformément au motif APG checkbox :

  • Tab déplace le focus sur la case à cocher.
  • Espace bascule aria-checked entre "true" et "false" (et "mixed" pour le tri-état).
  • Entrée n’active PAS une case à cocher — Espace uniquement. (Les inputs natifs ignorent aussi Entrée dans la plupart des navigateurs.)

Le focus reste sur la case à cocher après activation.

Erreurs fréquentes

  • role="checkbox" sans attribut aria-checked défini. L’état est obligatoire dès que l’élément est dans le DOM.
  • Utiliser aria-checked="true" uniquement comme hook de classe — mettre à jour l’apparence visuelle sans jamais mettre à jour l’attribut au clic.
  • Des cases à cocher personnalisées qui répondent au clic mais pas à Espace.
  • Imbriquer un <input> natif dans un <div role="checkbox"> — la sémantique dupliquée perturbe les lecteurs d’écran.
  • Des contrôles tri-états dont Espace cycle entre false → true → mixed → false. L’APG spécifie false → true → false ; mixed est défini programmatiquement par la page, pas par l’utilisateur.

Exemple

<!-- Préféré -->
<label>
  <input type="checkbox" name="terms" required>
  I agree to the terms
</label>

<!-- "Tout sélectionner" tri-état personnalisé -->
<div
  role="checkbox"
  tabindex="0"
  aria-checked="mixed"
  aria-labelledby="selectAllLabel"
>
</div>
<span id="selectAllLabel">Select all rows</span>