# Construire un mega-menu accessible pour un site de recrutement

> Un snippet complet pour un mega-menu de catégories de métiers, navigable aux flèches et fermé à l'Échap, sans bibliothèque tierce.

- Auteur : WordPress Développement
- Publié le : 2023-10-21
- Mis à jour le : 2023-10-21
- Catégorie : Accessibilité
- URL : https://www.wpmoderne.fr/accessibilite/mega-menu-accessible-site-recrutement/

## L’essentiel

- Flèches directionnelles entre colonnes
- Échap referme et rend le focus
- Aucune dépendance JavaScript externe

Comment un candidat qui navigue au clavier retrouve-t-il la catégorie « développement » dans un mega-menu de vingt métiers rangés en quatre colonnes ? C'est la question posée par un cabinet de recrutement qui refondait son site vitrine sous WordPress et voulait un menu de catégories professionnelles sans plugin de navigation.

Le brief tenait en une phrase : chaque colonne du mega-menu regroupe une famille de métiers (tech, marketing, finance, opérations), et un visiteur au clavier doit pouvoir circuler entre les liens avec les flèches, sans jamais perdre le focus ni tomber dans une impasse.

## Le problème : un menu à plat ne suffit pas

Un mega-menu HTML classique, construit avec des `<ul>` imbriqués, fonctionne déjà à la tabulation : chaque lien reçoit le focus dans l'ordre du DOM. Mais avec vingt liens répartis sur quatre colonnes, appuyer vingt fois sur `Tab` pour atteindre la dernière colonne décourage n'importe quel utilisateur. Il fallait donc ajouter une navigation par flèches, calquée sur le modèle *grid* décrit par les pratiques ARIA de la WAI, sans pour autant transformer le menu en widget complexe et fragile.

Deuxième contrainte : la fermeture. Un mega-menu ouvert au clic ou au focus doit se refermer proprement à la touche `Échap`, en renvoyant le focus sur le bouton qui l'a ouvert. Beaucoup d'implémentations maison oublient cette étape et laissent l'utilisateur clavier coincé dans un menu invisible.

> L'essentiel à retenir : Flèches directionnelles entre colonnes ; Échap referme et rend le focus ; Aucune dépendance JavaScript externe

## Le snippet : structure HTML et rôles

La structure repose sur un bouton natif suivi d'un conteneur de menu. Aucun rôle exotique n'est nécessaire : un `<button>` avec `aria-expanded` et `aria-controls`, et un conteneur classique.

```
<button id="menu-metiers-btn" aria-expanded="false" aria-controls="menu-metiers">
  Nos métiers
</button>
<div id="menu-metiers" class="mega-menu" hidden>
  <ul class="mega-menu__colonne">
    <li><a href="/metiers/developpement">Développement</a></li>
    <li><a href="/metiers/qa">Qualité logicielle</a></li>
  </ul>
  <ul class="mega-menu__colonne">
    <li><a href="/metiers/marketing">Marketing</a></li>
    <li><a href="/metiers/communication">Communication</a></li>
  </ul>
</div>
```

Le comportement d'ouverture bascule l'attribut `hidden` et met à jour `aria-expanded` : rien de plus, aucun rôle `menu` ou `menuitem`, qui imposeraient une gestion du focus beaucoup plus lourde et souvent mal maîtrisée.

## La navigation aux flèches, ligne par ligne

Le script écoute les événements clavier sur le conteneur et calcule la position du lien focalisé dans une grille virtuelle construite à partir des colonnes réelles du DOM.

```
const liens = [...menu.querySelectorAll('a')];
menu.addEventListener('keydown', (e) => {
  const index = liens.indexOf(document.activeElement);
  if (index === -1) return;
  if (e.key === 'ArrowDown') {
    e.preventDefault();
    liens[(index + 1) % liens.length].focus();
  }
  if (e.key === 'ArrowUp') {
    e.preventDefault();
    liens[(index - 1 + liens.length) % liens.length].focus();
  }
  if (e.key === 'Escape') {
    e.preventDefault();
    fermerMenu();
    document.getElementById('menu-metiers-btn').focus();
  }
});
```

Les flèches gauche et droite suivent le même principe, mais en sautant d'une colonne à l'autre plutôt que d'un lien au suivant : on additionne la taille d'une colonne à l'index courant. Ce calcul reste lisible parce que chaque colonne compte le même nombre approximatif de métiers ; avec des colonnes très déséquilibrées, mieux vaut stocker les index de colonne directement en attribut `data-colonne` sur chaque lien.

## Variantes selon le contexte

- Sur un thème basé sur les blocs, le mega-menu peut être injecté via un bloc personnalisé enregistré avec `register_block_type()`, ce qui permet aux rédacteurs de réordonner les colonnes de métiers sans toucher au code.
- Sur un site multilingue, chaque lien de métier doit garder son intitulé traduit dans l'attribut `lang` si la langue de la page cible diffère de la langue courante.
- Pour un menu à une seule colonne, la navigation par flèches redevient une simple liste verticale : autant simplifier le script plutôt que de forcer une logique de grille inutile.

### Un point souvent négligé : le survol à la souris

Un mega-menu qui ne s'ouvre qu'au survol pose un problème réel aux utilisateurs de trackpad ou de commande vocale : le menu peut s'ouvrir sans intention et masquer le contenu en dessous. La solution retenue ici combine clic et focus comme déclencheurs, et ignore volontairement le survol seul.

> Un menu qui s'ouvre au survol et se comporte différemment au clavier n'est pas un menu accessible avec un bonus clavier : c'est deux menus qui doivent rester synchronisés, et qui finissent toujours par diverger après la troisième mise à jour du thème.

## En résumé

Sept rôles et attributs ARIA (`aria-expanded`, `aria-controls`, `hidden`, et les gestionnaires de flèches et d'Échap) suffisent à rendre un mega-menu de recrutement pleinement utilisable au clavier, sans framework de composants ni bibliothèque de menu. Le vrai travail se situe dans les tests manuels : ouvrir, naviguer aux flèches jusqu'à la dernière colonne, refermer à l'Échap, vérifier que le focus revient bien sur le bouton d'origine. Ces quatre étapes, répétées à chaque modification du menu, évitent la régression silencieuse la plus fréquente sur ce type de composant.
