Normes · ARIA

Rôle Widget

combobox

Marque un champ texte associé à une liste contextuelle de valeurs — utilisé pour la saisie automatique, la recherche par anticipation et les selects personnalisés. Le natif <select> gère la sélection simple ; n'utilisez role="combobox" que pour le filtrage, le rendu personnalisé ou les suggestions distantes.

Quand l’utiliser

Utilisez <select> lorsque le choix provient d’une liste courte et fixe et que l’utilisateur n’a pas besoin de filtrer. L’élément natif offre des sélecteurs adaptés au mobile, un support clavier complet et aucun JavaScript.

role="combobox" est réservé aux cas que le natif ne peut pas couvrir :

  • Saisie automatique avec filtrage (recherche de ville, mention d’utilisateur).
  • Suggestions récupérées depuis une API distante.
  • Éléments rendus avec du contenu enrichi (avatars, texte secondaire).
  • Champs de tags où plusieurs valeurs peuvent être sélectionnées.

ARIA 1.2 a modifié significativement le motif combobox. Le rôle est placé sur le <input>, PAS sur le conteneur. La popup est un role="listbox" séparé (ou tree/grid/dialog) que le combobox possède via aria-controls.

Contrat clavier + focus

Conformément au motif APG combobox :

  • Le focus reste sur le champ en permanence. La listbox est ouverte via aria-expanded="true" et l’option active est suivie via aria-activedescendant, PAS en déplaçant le focus.
  • La flèche bas ouvre la popup et déplace l’option active sur le premier élément.
  • Les flèches haut/bas déplacent l’option active dans la popup.
  • Entrée sélectionne l’option active et ferme la popup.
  • Échap ferme la popup ; au second Échap, efface le champ.
  • La frappe filtre la liste (quand aria-autocomplete="list" ou "both").

Définissez aria-autocomplete à "none", "inline", "list" ou "both" pour décrire le comportement des suggestions.

Erreurs fréquentes

  • Placer role="combobox" sur le conteneur plutôt que sur le <input> (le motif pré-1.2). Les lecteurs d’écran modernes s’attendent à ce que le rôle soit sur l’élément éditable.
  • Déplacer le focus DOM dans la listbox sur flèche-bas. L’APG impose aria-activedescendant ; déplacer le focus interrompt la frappe.
  • aria-expanded bloqué à "false" même quand la popup est visible.
  • Listbox rendue dans le DOM mais jamais liée depuis aria-controls.
  • Filtrer la liste en laissant aria-activedescendant pointer vers un élément qui n’existe plus.

Exemple

<label for="city">City</label>
<input
  id="city"
  type="text"
  role="combobox"
  aria-controls="cityList"
  aria-expanded="false"
  aria-autocomplete="list"
  aria-activedescendant=""
>
<ul id="cityList" role="listbox" hidden>
  <li id="city-1" role="option">London</li>
  <li id="city-2" role="option">Lisbon</li>
  <li id="city-3" role="option">Ljubljana</li>
</ul>