ARIA : guide pratique des rôles et attributs
ARIA (Accessible Rich Internet Applications) est une spécification du W3C. Elle ajoute au HTML des rôles, des états et des propriétés, pour que les lecteurs d’écran et les autres technologies d’assistance comprennent les composants que le HTML ne décrit pas seul. Bien utilisé, ARIA rend accessibles des onglets ou des menus déroulants ; mal utilisé, il dégrade un site qui fonctionnait.
Ce que fait ARIA, et ce qu’il ne fait pas
ARIA modifie uniquement ce que le navigateur transmet aux technologies d’assistance (l’arbre d’accessibilité). Il ne change ni l’apparence, ni le comportement, ni la navigation au clavier : un role="button" ne rend pas une div cliquable au clavier.
Les rôles
Ce qu’est l’élément : role="tab", role="dialog", role="status"…
Les propriétés
Ses caractéristiques stables : aria-labelledby, aria-controls, aria-required…
Les états
Ce qui change à l’usage : aria-expanded, aria-selected, aria-checked, aria-invalid…
Les cinq règles d’utilisation
Le W3C résume le bon usage d’ARIA en cinq règles.
- Préférez l’élément HTML natif. Un <button>, un <a href>, un <input type="checkbox"> ou un <dialog> portent déjà leur rôle, leur état et leur comportement au clavier. ARIA ne sert que lorsqu’aucun élément natif ne convient.
- Ne changez pas la sémantique native sans nécessité. Un titre <h2 role="tab"> perd son rôle de titre. Placez plutôt l’onglet dans le titre : <h2><button role="tab">…</button></h2>.
- Tout composant ARIA interactif doit fonctionner au clavier. Un role="button" n’ajoute ni le focus ni la réaction aux touches Entrée et Espace : c’est à votre script de les fournir.
- Ne masquez jamais un élément qui reçoit le focus. role="presentation" ou aria-hidden="true" sur un élément focalisable crée un élément atteignable au clavier mais muet pour le lecteur d’écran.
- Tout élément interactif doit avoir un nom accessible. Un bouton, un lien ou un champ sans nom est restitué « bouton », « lien » ou « champ de saisie », sans indication de sa fonction.
<div class="btn" role="button" onclick="envoyer()">Envoyer</div>
<!-- Pas atteignable avec Tab, ne réagit ni à Entrée ni à Espace --><button type="button" class="btn" onclick="envoyer()">Envoyer</button>Donner un nom accessible
Le nom accessible est ce que le lecteur d’écran annonce. Il vient d’abord de aria-labelledby (le texte d’un autre élément), puis de aria-label (un texte fourni directement), puis du HTML : le contenu d’un bouton ou d’un lien, l’étiquette <label> d’un champ, l’attribut alt d’une image. aria-describedby ajoute une description, lue après le nom.
Lorsque le composant affiche un texte, son nom accessible doit le reprendre : un bouton affichant « Rechercher » ne doit pas s’appeler « Lancer la requête ».
<button type="button" class="close">
<svg viewBox="0 0 24 24"><path d="M6 6l12 12M18 6 6 18"/></svg>
</button>
<!-- Restitué « bouton », sans dire ce qu’il fait --><button type="button" class="close" aria-label="Fermer la fenêtre">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg>
</button>Masquer correctement avec aria-hidden
aria-hidden="true" retire un élément et tout son contenu de ce que perçoivent les technologies d’assistance, sans le masquer à l’écran. Il sert aux icônes décoratives et aux contenus redondants. Il ne doit jamais contenir un élément qui reçoit le focus, ni masquer une information utile.
<div class="promo" aria-hidden="true">
<a href="/soldes">Voir les soldes</a>
</div>
<!-- Le lien reçoit le focus mais n’est pas restitué : un « trou » au clavier --><a href="/soldes">
<svg aria-hidden="true" viewBox="0 0 24 24">…</svg>
Voir les soldes
</a>Annoncer un changement : les régions live
Un message qui apparaît sans déplacer le focus (« Article ajouté au panier », « 3 résultats ») doit être annoncé. role="status" l’annonce sans interrompre la lecture en cours ; role="alert" l’annonce immédiatement, à réserver aux erreurs et aux urgences. La région doit être présente dans la page avant que son texte ne change.
<script>
panier.insertAdjacentHTML("beforeend",
'<p role="status">Article ajouté au panier</p>');
</script>
<!-- Souvent non annoncé : la région n’existait pas avant le changement --><p id="panier-statut" role="status"></p>
<script>
document.getElementById("panier-statut").textContent = "Article ajouté au panier";
</script>Les composants les plus courants
Bouton de divulgation (menu déroulant, accordéon)
Un <button> avec aria-expanded="true" ou "false", mis à jour à chaque ouverture, et aria-controls vers le contenu affiché.
Onglets
Un conteneur role="tablist", des role="tab" avec aria-selected et aria-controls, des role="tabpanel" liés par aria-labelledby. Les flèches gauche et droite passent d’un onglet à l’autre.
Fenêtre modale
L’élément <dialog> ouvert avec showModal(), ou role="dialog" avec aria-modal="true" et aria-labelledby vers son titre. Le focus entre dans la fenêtre, Échap la ferme, et le focus revient sur le bouton qui l’a ouverte.
Navigation principale
Un élément <nav> avec une liste de liens, et des boutons de divulgation pour les sous-menus. Le rôle menu est réservé aux menus d’application (comme ceux d’un logiciel), pas à la navigation d’un site.
<button type="button" class="toggle">Nos services</button>
<ul class="submenu" hidden>…</ul>
<!-- Le lecteur d’écran ne sait pas si le menu est ouvert ou fermé --><button type="button" aria-expanded="false" aria-controls="services">Nos services</button>
<ul id="services" hidden>…</ul>
<script>
const bouton = document.querySelector('[aria-controls="services"]');
bouton.addEventListener("click", () => {
const ouvert = bouton.getAttribute("aria-expanded") === "true";
bouton.setAttribute("aria-expanded", String(!ouvert));
document.getElementById("services").hidden = ouvert;
});
</script>Le W3C décrit le rôle, les attributs et le comportement au clavier attendus de chaque composant dans l’ARIA Authoring Practices Guide.
Les erreurs les plus fréquentes
- role="button" sur une div sans tabindex="0" ni gestion des touches Entrée et Espace.
- aria-label sur une div ou un span sans rôle : l’attribut n’y est pas autorisé et les lecteurs d’écran l’ignorent souvent.
- aria-hidden="true" sur un bloc qui contient un lien ou un bouton.
- aria-expanded qui reste à "false" quand le menu est ouvert.
- aria-labelledby ou aria-describedby qui pointent vers un id inexistant.
- Deux zones <nav> sans aria-label pour les distinguer (« Navigation principale », « Pied de page »).
- role="menu" pour la navigation du site, qui impose aux utilisateurs de lecteurs d’écran un mode de navigation inattendu.
- Un aria-label différent du texte visible : un utilisateur de commande vocale qui prononce le texte affiché ne peut pas activer le bouton.
ARIA dans les critères du RGAA
| Critère | Ce qu’ARIA permet ou impose |
|---|---|
| 1.1 | Alternative d’une image SVG porteuse d’information : role="img" et aria-label ou aria-labelledby. |
| 1.2 | Image de décoration ignorée : aria-hidden="true" sur un SVG décoratif. |
| 6.1 | Lien explicite : son intitulé peut venir d’un aria-label ou d’un aria-labelledby. |
| 7.1 | Composants scriptés compatibles avec les technologies d’assistance : rôles, états et propriétés corrects. |
| 7.5 | Messages de statut restitués : role="status", role="alert" ou aria-live. |
| 10.8 | Contenus cachés : aria-hidden ne doit masquer que ce qui a vocation à être ignoré. |
| 11.1 | Étiquette d’un champ : aria-labelledby ou aria-label lorsque <label> ne convient pas. |
| 11.10 | Contrôle de saisie : champs obligatoires et erreurs signalés, par exemple avec aria-required et aria-invalid. |
| 12.6 | Zones de regroupement : en-tête, navigation, contenu principal et pied de page identifiés (éléments HTML ou rôles ARIA). |
Comment tester
- Au clavier seul. Tab, Maj+Tab, Entrée, Espace, Échap et les flèches doivent suffire à utiliser chaque composant, avec un focus toujours visible.
- Dans l’arbre d’accessibilité. Le panneau Accessibilité des outils de développement de Chrome ou de Firefox montre le rôle, le nom et les états de chaque élément.
- Avec un lecteur d’écran. NVDA (gratuit, Windows), VoiceOver (macOS et iOS) ou TalkBack (Android) : écoutez ce qui est annoncé à l’ouverture d’un menu ou à l’envoi d’un formulaire.
- Avec un outil automatique. Il repère les attributs invalides, les références cassées et les composants sans nom. Le pré-audit gratuit les relève sur vos pages.
Questions fréquentes
ARIA est-il obligatoire pour être conforme au RGAA ?
Non. Le RGAA demande que les composants soient compatibles avec les technologies d’assistance. Avec des éléments HTML natifs, c’est souvent déjà le cas. ARIA devient nécessaire pour les composants qui n’ont pas d’équivalent natif : onglets, menus déroulants, messages de statut.
Faut-il utiliser aria-label ou un texte masqué visuellement ?
Les deux donnent un nom accessible. Un texte visible reste préférable. Le texte masqué visuellement a l’avantage d’être traduit par les outils de traduction automatique, qui ignorent souvent aria-label.
aria-hidden et display: none, quelle différence ?
display: none et l’attribut hidden masquent l’élément pour tout le monde. aria-hidden="true" le laisse visible à l’écran mais le retire de ce que perçoivent les technologies d’assistance : à réserver aux éléments décoratifs ou redondants.
Un outil automatique peut-il vérifier ARIA ?
En partie. Il détecte les rôles et attributs invalides, les attributs obligatoires manquants, les références vers des id inexistants, les éléments focalisables masqués et les composants sans nom. Il ne peut pas juger si le nom est pertinent ni si le composant se comporte correctement : cela demande un contrôle humain.
Sources : spécification WAI-ARIA 1.2 et Using ARIA (W3C), RGAA 4.1.2.