vendredi 25 septembre 2026

À propos

Contact

Accessibilité

Construire un sélecteur de couleurs de thème accessible sans piège au clavier

Un réglage de personnalisation de thème enfermait le focus dans sa fenêtre flottante sans moyen d'en sortir au clavier. Tutoriel pour construire un sélecteur qui n'enferme personne.

Par Clément Hadrot • 6 novembre 2024 • 4 min de lecture • Aucun commentaire
Construire un sélecteur de couleurs de thème accessible sans piège au clavier

Un client personnalisant lui-même les couleurs d’accentuation de son thème via un réglage maison ajouté au Customizer avait signalé un blocage complet : une fois le sélecteur de couleurs ouvert, impossible de le refermer sans réactualiser la page. Ce tutoriel construit, étape par étape, un sélecteur de couleurs accessible qui évite ce piège, sans revenir sur la vérification du contraste des couleurs une fois choisies, déjà traitée dans un autre article.

Étape 1 : identifier la structure du composant

Le sélecteur affiche une grille de pastilles de couleur prédéfinies, plus un champ de saisie libre au format hexadécimal, dans un panneau flottant ouvert au clic sur un bouton d’aperçu de la couleur actuelle. Cette structure correspond à un motif ARIA reconnu, proche d’une combobox ou d’un menu déroulant complexe, ce qui impose des règles précises de gestion du clavier, faute de quoi le composant devient soit invisible pour un lecteur d’écran, soit littéralement bloquant.

Étape 2 : ouvrir le panneau avec un état correctement annoncé

Le bouton qui ouvre le panneau doit porter aria-haspopup="true" et un état aria-expanded qui bascule entre "false" et "true" à l’ouverture :

<button
  type="button"
  aria-haspopup="true"
  aria-expanded="false"
  aria-label="Choisir la couleur d'accentuation, actuellement bleu marine">
  <span class="apercu-couleur" style="background-color:#1e3a8a"></span>
</button>

Étape 3 : la faute qui créait le piège

Le composant initial capturait tous les événements keydown du document dès l’ouverture du panneau, pour permettre de naviguer entre les pastilles avec les flèches du clavier. Le problème : ce gestionnaire interceptait aussi la touche Échap, mais sans jamais appeler la fonction de fermeture — un oubli pur et simple dans le code d’origine, qui laissait la personne coincée dans le panneau sans aucune sortie clavier possible.

L'essentiel à retenir : Un piège de focus non maîtrisé bloque totalement la navigation clavier ; Escape doit toujours permettre de fermer et de rendre le focus à l'élément déclencheur ; Les cases de couleur doivent rester navigables aux flèches, pas seulement à Tab
// Avant : Échap capturée mais jamais traitée
document.addEventListener('keydown', (e) => {
  if (e.key === 'ArrowRight') deplacerSelectionA(1);
  if (e.key === 'ArrowLeft') deplacerSelectionA(-1);
  // aucune ligne pour 'Escape' : le piège vient de là
});
// Après : Échap ferme systématiquement et restitue le focus
document.addEventListener('keydown', (e) => {
  if (e.key === 'ArrowRight') deplacerSelectionA(1);
  if (e.key === 'ArrowLeft') deplacerSelectionA(-1);
  if (e.key === 'Escape') {
    fermerPanneau();
    boutonDeclencheur.focus();
  }
});

Étape 4 : rendre les pastilles navigables aux flèches, pas seulement à Tab

Une grille de couleurs se navigue naturellement aux flèches directionnelles, pas en tabulant pastille par pastille, ce qui serait à la fois lent et contre-intuitif pour qui connaît déjà ce type de composant. La grille utilise donc un seul élément dans l’ordre de tabulation (tabindex="0" sur la pastille sélectionnée, tabindex="-1" sur les autres), et les flèches déplacent le focus logique à l’intérieur de la grille :

  • Flèche droite / gauche : pastille suivante ou précédente sur la même ligne.
  • Flèche haut / bas : pastille équivalente sur la ligne au-dessus ou en dessous.
  • Entrée ou Espace : valide la couleur sélectionnée et ferme le panneau.
  • Échap : ferme le panneau sans valider, restitue le focus au bouton déclencheur.

Étape 5 : vérifier le champ de saisie hexadécimale en parallèle

Le champ de saisie libre, pour une couleur hors de la grille prédéfinie, doit rester un champ de formulaire standard avec un <label> explicite (« Couleur personnalisée, format hexadécimal ») et ne doit jamais être capturé par le même gestionnaire de flèches que la grille, sous peine d’empêcher tout déplacement du curseur de texte pendant la saisie — un second piège plus discret rencontré pendant les tests de ce composant.

Étape 6 : tester le cycle complet d’ouverture et de fermeture

Le test final consiste à ouvrir le panneau au clavier, naviguer dans la grille aux flèches, valider une couleur avec Entrée, puis rouvrir le panneau et le fermer cette fois avec Échap sans valider, en vérifiant à chaque fois que le focus revient précisément sur le bouton déclencheur, jamais sur body ni ailleurs dans la page.

Un piège de focus n’est presque jamais voulu : il vient d’un gestionnaire d’événements qui capture une touche sans prévoir tous les cas de sortie. La checklist la plus utile reste simple : chaque fois qu’un composant capture keydown globalement, vérifier explicitement que Échap y est traitée.

En résumé

Ce sélecteur de couleurs, bloquant à l’origine par un simple oubli de gestion de la touche Échap, est devenu, après correction, un exemple réutilisable de grille de couleurs accessible : ouverture annoncée par aria-expanded, navigation aux flèches à l’intérieur de la grille, et sortie garantie par Échap avec restitution du focus. Le contraste des couleurs elles-mêmes reste un sujet distinct, déjà traité par ailleurs.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi