role="tablist", role="tab", role="tabpanel" : trois rôles ARIA suffisent à transformer un simple jeu d’onglets en composant réellement navigable au clavier, à condition de respecter précisément le motif de conception attendu par les lecteurs d’écran. C’est la recette utilisée pour construire le planning d’un festival de musique répartis sur quatre jours, où chaque journée devait s’afficher sans rechargement de page tout en restant annoncée clairement.
Le programme est enregistré comme type de contenu personnalisé evenement, avec un champ de taxonomie jour_festival pour classer chaque concert. Le rendu HTML est généré en PHP côté serveur, puis le changement d’onglet est géré en JavaScript côté client, sans dépendance à une bibliothèque tierce.
Générer la structure PHP
La fonction suivante construit la liste des onglets et les panneaux correspondants à partir des termes de taxonomie enregistrés :
function wpm_programme_festival() {
$jours = get_terms([
'taxonomy' => 'jour_festival',
'hide_empty' => true,
]);
if (empty($jours) || is_wp_error($jours)) {
return;
}
echo '<div class="programme-festival">';
echo '<div role="tablist" aria-label="Jours du festival">';
foreach ($jours as $index => $jour) {
$actif = $index === 0 ? 'true' : 'false';
$tabindex = $index === 0 ? '0' : '-1';
printf(
'<button role="tab" id="tab-%1$s" aria-controls="panel-%1$s" aria-selected="%2$s" tabindex="%3$s">%4$s</button>',
esc_attr($jour->slug),
esc_attr($actif),
esc_attr($tabindex),
esc_html($jour->name)
);
}
echo '</div>';
foreach ($jours as $index => $jour) {
$cache = $index === 0 ? '' : 'hidden';
printf(
'<div role="tabpanel" id="panel-%1$s" aria-labelledby="tab-%1$s" %2$s>',
esc_attr($jour->slug),
esc_attr($cache)
);
wpm_liste_concerts_du_jour($jour->term_id);
echo '</div>';
}
echo '</div>';
}
Chaque bouton reçoit un aria-controls qui pointe vers le panneau correspondant, et un seul onglet fait partie de l’ordre de tabulation par défaut (tabindex="0"), les autres étant accessibles ensuite par les flèches directionnelles.
Gérer le changement de jour en JavaScript

Le script ci-dessous applique le motif de conception « tablist » recommandé : les flèches gauche et droite déplacent le focus entre les onglets, la touche Entrée ou Espace active le panneau correspondant.
const onglets = Array.from(document.querySelectorAll('[role="tab"]'));
function activerOnglet(cible) {
onglets.forEach((onglet) => {
const estCible = onglet === cible;
onglet.setAttribute('aria-selected', estCible);
onglet.setAttribute('tabindex', estCible ? '0' : '-1');
const panneau = document.getElementById(onglet.getAttribute('aria-controls'));
panneau.hidden = !estCible;
});
cible.focus();
}
onglets.forEach((onglet, index) => {
onglet.addEventListener('click', () => activerOnglet(onglet));
onglet.addEventListener('keydown', (evenement) => {
let prochain = null;
if (evenement.key === 'ArrowRight') prochain = onglets[index + 1] || onglets[0];
if (evenement.key === 'ArrowLeft') prochain = onglets[index - 1] || onglets[onglets.length - 1];
if (prochain) activerOnglet(prochain);
});
});
Le focus se déplace physiquement vers l’onglet activé, ce qui garantit qu’un lecteur d’écran annonce immédiatement le nouveau jour sélectionné, sans que l’utilisateur ait besoin d’appuyer une seconde fois sur Tab.
Vérifier l’annonce du jour actif
Le test au lecteur d’écran doit confirmer une annonce du type « Vendredi, onglet, sélectionné, 1 sur 4 ». Cette annonce dépend entièrement de la présence correcte de aria-selected et du rôle tab : sans eux, le lecteur d’écran se contente d’annoncer « bouton », sans indiquer ni la sélection ni la position dans le groupe.
- Vérifier que seul l’onglet actif possède
tabindex="0"; - Vérifier que le panneau masqué porte bien l’attribut
hidden, et pas seulement une classe CSS ; - Vérifier que le focus visuel suit le focus réel après chaque changement de jour.
Notre verdict
Un lecteur de programme d’événementiel bien construit ne nécessite aucune extension : trois rôles ARIA, une fonction PHP de rendu et une trentaine de lignes de JavaScript suffisent à obtenir un composant qui se comporte exactement comme les onglets natifs attendus par les technologies d’assistance, tout en restant entièrement personnalisable dans son style visuel.