Les boîtes de dialogue 1/2

Préambule

Les boîtes de dialogue font partie des composants que l’on retrouve régulièrement sur un site web. Malheureusement il n’existe pas de composant natif HTML permettant de créer ce type d’objet. Elles doivent donc être créées de toute pièce lors du développement, phase qui introduit souvent des problèmes d’accessibilité si on n’y prête pas attention.

Les boîtes de dialogue présentent souvent de cruelles difficultés, jusqu’à une complète inaccessibilité pour les utilisateurs qui naviguent à l’aide du clavier (touche Tab), ou celles qui naviguent à l’aide d’un lecteur d’écran (personnes malvoyantes ou non-voyantes). Cet exemple liste pas à pas les différentes étapes nécessaires pour créer une boîte de dialogue accessible.

Rappel ergonomie : il faut éviter l’emploi des boîtes de dialogue, fenêtres modales et autres popins, en particulier pour afficher de l’information, car leur utilisabilité et lisibilité sont problématiques pour tous les utilisateurs. Ne réserver leur emploi qu’à une petite quantité d’information avec un appel à action (validation d’une action, confirmation d’effacement de données…).

Si vous ne souhaitez pas créer ce composant de toute pièce, vous pouvez également utiliser le composant « modal » de la librairie Boosted qui présente le double avantage d’être accessible et d’être déjà aux couleurs de la charte Orange.

Exemple final

Voici le rendu final de la boîte de dialogue dont nous allons expliquer la création pas à pas dans cet exemple.

Étape 1 : définition du squelette

Nous créons ici le squelette de notre boîte de dialogue à l’aide d’une balise <div>. Nous lui ajoutons :

Avertissement

Je suis une boîte de dialogue modale. Je suis accessible à la souris, au clavier et au lecteur d’écran.


<div class="dialog">
  <div class="dialogContainer">
    <button>X</button>
    <h1>Avertissement</h1>
    <p>Je suis une boîte de dialogue modale. Je suis accessible à la souris, au clavier et au lecteur d’écran.</p>
    <button>J’ai compris</button>
    <button>Annuler</button>
  </div>
</div>

Place aux tests

Étape 2 : gérer la navigation au clavier

Pour que l’on puisse naviguer correctement à l’aide du clavier :

Dans ce nouvel exemple, on mémorise l’emplacement du focus à l’ouverture :


  // Récupère l'élément boîte de dialogue
  const dialog =  document.getElementById('step2-dialog');

  // Sauvegarde le focus pour le repositionner à la fermeture
  dialog.setAttribute('data-focusBack', 'step2-openButton');

  // Place le focus sur l’élément par défaut
  dialog.querySelector('.defaultFocus').focus();

On repositionne le focus lors de la fermeture :


  // Repositionne le focus à la fermeture de la dialogue
  var focusBackElement = dialog.getAttribute('data-focusBack');
  document.getElementById(focusBackElement).focus();

On empêche le focus de sortir de la boîte de dialogue.

Pour cela nous nous appuyons sur la méthode querySelectorAll. Elle nous permettra de récupérer facilement les éléments interactifs de la boîte de dialogue, pour ensuite identifier le premier élément et le dernier élément de la boîte.

Enfin à l'aide du gestionnaire d'évènement onKeyDown, nous pourrons intercepter le focus lorsqu'il arrivera sur le premier ou le dernier item, pour le repositionner en début ou en fin de modale, selon notre besoin.

La solution détaillée est présentée dans cet article : How to trap focus inside modal to make it ADA compliant


  // Récupère le premier élément interactif
  const dialogStart = finalDialog.querySelectorAll('button')[0];
  
  // Récupère le dernier élément interactif
  const dialogFocusableContent = dialog.querySelectorAll('button');
  const dialogStop = dialogFocusableContent[finalFocusableContent.length - 1];

  // Ecoute le parcours clavier, et repositionne le focus si nécessaire en fonction de l'élément actif
  dialog.onkeydown = function(e){
	
	if (e.key === 'Tab' || e.keyCode === 9) {
		
		if ( e.shiftKey ) {
		  if (document.activeElement === dialogStart) {
			e.preventDefault();
			dialogStop.focus();
		  }
		} else /* tab */ {
		  if (document.activeElement === dialogStop) {
			e.preventDefault();
			dialogStart.focus();
		  }
		}
	}
  }

Avertissement

Je suis une boîte de dialogue modale. Je suis accessible à la souris, au clavier et au lecteur d’écran.

On écoute également l’événement onKeyDown pour fermer la dialogue lorsque la touche Échap est pressée.

Voici le code HTML à jour de la boîte de dialogue :


<div id="step2-dialog" class="dialog">
  <div class="dialogContainer">
    <button>X</button>
    <h1>Avertissement</h1>
    <p>Je suis une boîte de dialogue modale. Je suis accessible à la souris, au clavier et au lecteur d’écran.</p>
    <button class="defaultFocus">J’ai compris</button>
    <button>Annuler</button>
  </div>
</div>

Place aux tests

Étape 3 : gérer la navigation au lecteur d’écran

Pour que l’on puisse naviguer correctement à l’aide d’un lecteur d’écran :

L’attribut aria-labelledby permet d’indiquer l’id de l’élément contenant le titre de la boîte de dialogue. Celui-ci sera vocalisé automatiquement par le lecteur d’écran. L’attribut aria-describedby permet d’indiquer l’id de l’élément contenant la description. Cette description sera vocalisée automatiquement après le titre de la boîte de dialogue. Enfin l’attribut aria-label sur le bouton de fermeture « X » permet de spécifier un libellé à vocaliser (sinon par défaut celui-ci sera vocalisé : « x »).


<div id="final-dialog" role="dialog" aria-labelledby="final-dialogTitle" aria-describedby="final-description">
  <div class="dialogContainer">
    <button aria-label="fermer" title="Fermer">X</button>
    <h1 id="final-dialogTitle">Avertissement</h1>
    <p id="final-description">Je suis une boîte de dialogue modale. Je suis accessible à la souris, au clavier et au lecteur d’écran.</p>
    <button class="defaultFocus">J’ai compris</button>
    <button>Annuler</button>
  </div>
</div>

Place aux tests

Note sur la navigation à l’aide du lecteur d’écran

Dans une page web, la navigation au lecteur d’écran s’effectue principalement à l’aide des touches Flèche haut et Flèche bas. Ce mode de navigation est appelé « mode document ». On peut également utiliser la touche Tab mais dans ce cas seuls les éléments focusables seront vocalisés.

Dans les applications natives, la navigation s’effectue principalement à l’aide de la touche Tab. Ce mode de navigation est appelé « mode application ». L’utilisation du rôle ARIA dialog, passe le lecteur d’écran dans le « mode application », c’est à dire que la navigation avec les flèches n’est plus disponible lorsqu’une boîte de dialogue est affichée. Dans ce cas il faut utiliser la touche Tab pour naviguer entre les différents boutons de la dialogue.

À noter qu’il est également possible de forcer l’utilisation du mode « application » ou « document » à l’aide de l’attribut role. Cependant les utilisateurs n’étant pas habitués à ces changements de modes de navigation il est pour le moment déconseillé de les utiliser, sauf cas exceptionnels :


<div role="application">…</div>
<div role="document">…</div>