« Content on Hover or Focus » : c’est l’intitulé exact du critère de succès 1.4.13 de la spécification WCAG 2.1, qui pose trois conditions cumulatives pour tout contenu supplémentaire affiché au survol de la souris ou à la prise de focus clavier — rejetable, visible au survol comme au focus, et persistant tant que le pointeur ou le focus s’y trouve.
Cette recette construit une infobulle de thème WordPress qui respecte ces trois conditions, sans dépendre d’une bibliothèque JavaScript tierce. Elle ne traite pas de la proposition d’un attribut popover natif du HTML, encore à l’étude, qui mériterait un traitement à part entière.
Le problème de départ
L’infobulle la plus courante sur le web repose uniquement sur la pseudo-classe CSS :hover, appliquée à une icône d’information à côté d’un champ de formulaire :
.wpm-info-icone:hover .wpm-info-bulle {
display: block;
}
Cette approche échoue sur deux points du critère 1.4.13 : un utilisateur qui navigue au clavier, sans souris, n’a aucun moyen de déclencher :hover, donc l’infobulle ne s’affiche jamais pour lui. Et même pour un utilisateur à la souris, dès que le curseur quitte l’icône d’un pixel, le contenu disparaît, ce qui empêche de sélectionner ou de lire tranquillement un texte un peu long.
La structure HTML de départ
Le balisage associe un bouton — pas un simple span, pour rester focalisable nativement — à un conteneur de texte relié par aria-describedby :
<label for="code-postal">Code postal</label>
<button type="button" class="wpm-info-icone" aria-describedby="aide-code-postal">
<span aria-hidden="true">?</span>
<span class="wpm-sr-only">Aide sur le code postal</span>
</button>
<div id="aide-code-postal" class="wpm-info-bulle" hidden>
Saisissez les cinq chiffres du code postal, sans espace.
</div>
<input type="text" id="code-postal" name="code_postal">

Le script qui satisfait les trois conditions
Le script écoute à la fois les événements de souris et de clavier, sur le déclencheur comme sur l’infobulle elle-même, pour que le contenu reste affiché tant que l’un des deux s’y trouve :
document.querySelectorAll( '.wpm-info-icone' ).forEach( function ( declencheur ) {
var idBulle = declencheur.getAttribute( 'aria-describedby' );
var bulle = document.getElementById( idBulle );
var minuteur;
function afficher() {
clearTimeout( minuteur );
bulle.hidden = false;
}
function masquerAvecDelai() {
minuteur = setTimeout( function () {
bulle.hidden = true;
}, 150 );
}
declencheur.addEventListener( 'mouseenter', afficher );
declencheur.addEventListener( 'focus', afficher );
declencheur.addEventListener( 'mouseleave', masquerAvecDelai );
declencheur.addEventListener( 'blur', masquerAvecDelai );
bulle.addEventListener( 'mouseenter', afficher );
bulle.addEventListener( 'mouseleave', masquerAvecDelai );
declencheur.addEventListener( 'keydown', function ( evenement ) {
if ( evenement.key === 'Escape' ) {
bulle.hidden = true;
}
} );
} );
Trois éléments méritent une lecture attentive. D’abord, l’événement focus sur le déclencheur affiche l’infobulle exactement comme mouseenter, ce qui couvre l’exigence « visible au focus ». Ensuite, le court délai avant masquage laisse le temps au pointeur de passer du bouton au contenu de l’infobulle sans la faire disparaître entre les deux, ce qui satisfait l’exigence de persistance. Enfin, la touche Échap referme l’infobulle sans déplacer le focus ailleurs : il reste sur le bouton déclencheur, prêt pour l’action suivante.
Vérifier la troisième condition : le contenu reste consultable
Le troisième volet du critère — « rejetable » — impose qu’il existe un moyen de fermer le contenu sans déplacer le pointeur ni le focus, ce que la touche Échap couvre déjà. Il impose aussi implicitement que le contenu ne disparaisse pas tant que l’utilisateur ne l’a pas fermé ou n’a pas déplacé son attention ailleurs, condition remplie par le délai de masquage et par l’écoute des événements sur la bulle elle-même.
Conseil maison : tester cette infobulle uniquement au clavier, sans toucher la souris, du début à la fin d’un parcours de formulaire — c’est la façon la plus rapide de repérer un oubli d’événement
focusoublur.
Variantes possibles
Pour un contenu d’infobulle plus long qu’une phrase, mieux vaut basculer vers un lien qui ouvre une section d’aide dédiée plutôt que de multiplier les infobulles longues, qui deviennent pénibles à consulter au clavier sur un parcours de formulaire chargé. Pour un site qui gère déjà plusieurs infobulles similaires, factoriser ce script en une petite fonction réutilisable, prenant le sélecteur en paramètre, évite la duplication d’un template à l’autre.
Notre verdict
Construire une infobulle conforme au critère 1.4.13 ne demande ni bibliothèque, ni complexité excessive : quelques événements clavier ajoutés à côté des événements de souris suffisent. Le principal risque reste d’oublier l’un des trois volets du critère — rejetable, persistant, accessible au focus — en ne testant l’infobulle qu’à la souris, ce qui masque justement le problème que ce critère cherche à corriger.