Guides

Guide Complet ARIA : Rôles, Propriétés, États et Bonnes Pratiques

Qu'est-ce qu'ARIA ?

ARIA (Accessible Rich Internet Applications) est une spécification du W3C qui définit un ensemble d'attributs HTML permettant de rendre les contenus web dynamiques et les composants d'interface interactifs accessibles aux technologies d'assistance, en particulier les lecteurs d'écran. ARIA comble le fossé entre les possibilités d'interaction des applications web modernes et les informations que le HTML sémantique seul peut transmettre.

Dans le contexte du RGAA 4.1, ARIA intervient dans de nombreux critères, notamment ceux des thématiques 7 (Scripts), 9 (Structuration), 11 (Formulaires) et 12 (Navigation). Une utilisation correcte d'ARIA est donc essentielle pour la conformité RGAA.

Cependant, ARIA est souvent mal utilisé. Mal employé, il peut dégrader l'accessibilité au lieu de l'améliorer. La première règle d'ARIA — et la plus importante — est de ne l'utiliser que lorsque le HTML sémantique natif ne suffit pas.

Les 5 règles d'or d'ARIA

Le W3C a formulé cinq règles fondamentales pour l'utilisation d'ARIA. Les connaître et les respecter évite la majorité des erreurs courantes :

  1. Règle 1 : Préférez le HTML natif — Si un élément HTML natif existe avec la sémantique et le comportement souhaités, utilisez-le plutôt qu'un élément générique avec ARIA. Par exemple, utilisez <button> plutôt que <div role="button">.
  2. Règle 2 : Ne changez pas la sémantique native — N'ajoutez pas un rôle ARIA qui contredit la sémantique de l'élément HTML. Par exemple, n'écrivez pas <h2 role="tab">.
  3. Règle 3 : Clavier obligatoire — Tout composant interactif ARIA doit être utilisable au clavier. Si vous créez un role="button" sur un <div>, vous devez ajouter tabindex="0" et gérer les événements clavier (Entrée, Espace).
  4. Règle 4 : Ne masquez pas les éléments focusables — N'utilisez pas role="presentation" ou aria-hidden="true" sur un élément visible et focusable.
  5. Règle 5 : Les éléments interactifs ont un nom accessible — Tout élément interactif doit avoir un nom accessible (via le contenu textuel, aria-label, aria-labelledby ou le label associé).

Les trois types d'attributs ARIA

Rôles (roles)

Les rôles définissent le type de composant d'interface. Ils indiquent aux technologies d'assistance ce qu'est l'élément et comment il doit se comporter.

CatégorieRôles courantsUsage
Landmarksbanner, navigation, main, complementary, contentinfo, search, form, regionZones principales de la page
Widgetsbutton, checkbox, dialog, menuitem, tab, tabpanel, slider, switch, tooltipComposants interactifs
Structurelist, listitem, table, row, cell, heading, img, separatorStructure du document
Live regionsalert, status, log, marquee, timerZones de contenu dynamique

Propriétés (properties)

Les propriétés donnent des informations supplémentaires sur un élément. Elles sont généralement statiques ou changent rarement.

  • aria-label — Donne un nom accessible à un élément quand le texte visible ne suffit pas.
  • aria-labelledby — Associe un élément à un autre élément qui lui sert de label (par son id).
  • aria-describedby — Associe une description complémentaire à un élément.
  • aria-required — Indique qu'un champ de formulaire est obligatoire.
  • aria-haspopup — Indique qu'un élément ouvre un popup (menu, dialog, listbox).
  • aria-controls — Identifie l'élément contrôlé par cet élément.
  • aria-owns — Définit une relation parent-enfant dans le DOM quand la hiérarchie visuelle ne correspond pas au DOM.
  • aria-live — Définit une zone dont le contenu sera annoncé dynamiquement par les lecteurs d'écran.
  • aria-atomic — Indique si toute la zone live doit être annoncée ou seulement les changements.
  • aria-relevant — Définit quels types de changements sont annoncés (additions, removals, text, all).

États (states)

Les états reflètent l'état actuel d'un composant. Ils changent fréquemment en réponse aux interactions de l'utilisateur.

  • aria-expanded — Indique si un élément extensible (accordéon, menu) est ouvert (true) ou fermé (false).
  • aria-selected — Indique si un élément est sélectionné (onglet, option de liste).
  • aria-checked — Indique l'état d'une case à cocher ou d'un bouton radio.
  • aria-pressed — Indique l'état d'un bouton à bascule (toggle button).
  • aria-disabled — Indique qu'un élément est désactivé.
  • aria-invalid — Indique qu'une saisie de formulaire est invalide.
  • aria-hidden — Masque un élément pour les technologies d'assistance (mais il reste visible visuellement).
  • aria-current — Indique l'élément actuel dans un ensemble (page courante dans une navigation, étape courante d'un processus).
  • aria-busy — Indique qu'un élément est en cours de mise à jour.

Patterns ARIA courants

Menu de navigation

Le menu de navigation est l'un des composants les plus courants. Pour la navigation accessible, utilisez les landmarks ARIA :

<nav aria-label="Menu principal">
  <ul role="menubar">
    <li role="none">
      <a role="menuitem" href="/" aria-current="page">Accueil</a>
    </li>
    <li role="none">
      <button
        role="menuitem"
        aria-haspopup="true"
        aria-expanded="false"
        @click="toggleSubmenu"
        @keydown="handleMenuKeydown"
      >
        Produits
      </button>
      <ul role="menu" v-show="isOpen">
        <li role="none">
          <a role="menuitem" href="/produit-a">Produit A</a>
        </li>
        <li role="none">
          <a role="menuitem" href="/produit-b">Produit B</a>
        </li>
      </ul>
    </li>
  </ul>
</nav>

Le menu doit être navigable avec les touches fléchées (haut/bas pour les sous-menus, gauche/droite pour les items de premier niveau) et fermable avec Échap.

Onglets (Tabs)

<div>
  <div role="tablist" aria-label="Informations produit">
    <button
      role="tab"
      id="tab-description"
      aria-selected="true"
      aria-controls="panel-description"
    >
      Description
    </button>
    <button
      role="tab"
      id="tab-specs"
      aria-selected="false"
      aria-controls="panel-specs"
      tabindex="-1"
    >
      Caractéristiques
    </button>
    <button
      role="tab"
      id="tab-avis"
      aria-selected="false"
      aria-controls="panel-avis"
      tabindex="-1"
    >
      Avis clients
    </button>
  </div>

  <div
    role="tabpanel"
    id="panel-description"
    aria-labelledby="tab-description"
  >
    <p>Contenu de la description...</p>
  </div>

  <div
    role="tabpanel"
    id="panel-specs"
    aria-labelledby="tab-specs"
    hidden
  >
    <p>Contenu des caractéristiques...</p>
  </div>
</div>

Navigation au clavier : flèches gauche/droite pour passer d'un onglet à l'autre, Tab pour entrer dans le panel actif. Seul l'onglet actif a tabindex="0" (les autres ont tabindex="-1").

Modale (Dialog)

<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="modal-title"
  aria-describedby="modal-desc"
>
  <h2 id="modal-title">Confirmer la suppression</h2>
  <p id="modal-desc">
    Voulez-vous vraiment supprimer cet article ?
    Cette action est irréversible.
  </p>

  <button @click="confirm">Supprimer</button>
  <button @click="close" ref="closeBtn">Annuler</button>
</div>

<!-- Gestion du focus -->
<script>
// À l'ouverture : placer le focus dans la modale
// Piéger le focus dans la modale (Tab/Shift+Tab)
// À la fermeture : replacer le focus sur l'élément déclencheur
// Fermer avec Échap
</script>

La gestion du focus est le point le plus critique des modales. Le focus doit être piégé dans la modale (Tab et Shift+Tab ne sortent pas de la modale), la touche Échap ferme la modale, et à la fermeture le focus revient sur l'élément qui l'a ouverte.

Accordéon

<div>
  <h3>
    <button
      aria-expanded="true"
      aria-controls="section-1"
      id="header-1"
    >
      Première section
    </button>
  </h3>
  <div
    id="section-1"
    role="region"
    aria-labelledby="header-1"
  >
    <p>Contenu de la première section...</p>
  </div>

  <h3>
    <button
      aria-expanded="false"
      aria-controls="section-2"
      id="header-2"
    >
      Deuxième section
    </button>
  </h3>
  <div
    id="section-2"
    role="region"
    aria-labelledby="header-2"
    hidden
  >
    <p>Contenu de la deuxième section...</p>
  </div>
</div>

Zone de contenu dynamique (Live region)

Les live regions sont indispensables pour annoncer les changements de contenu aux lecteurs d'écran. Elles sont essentielles pour les sites e-commerce (ajout au panier, mises à jour) et toute interface dynamique.

<!-- Annonce non urgente (ne coupe pas l'utilisateur) -->
<div aria-live="polite" role="status">
  
</div>

<!-- Annonce urgente (interrompt l'utilisateur) -->
<div aria-live="assertive" role="alert">
  
</div>

<!-- Règles d'utilisation -->
<!-- 
  - "polite" : pour les confirmations, mises à jour non critiques
  - "assertive" : pour les erreurs, alertes urgentes uniquement
  - La zone doit exister dans le DOM AVANT le changement de contenu
  - Ne pas en abuser : trop d'annonces noient les informations importantes
-->

Nommer les éléments : aria-label vs aria-labelledby

Savoir quand utiliser aria-label et quand utiliser aria-labelledby est une compétence fondamentale :

AttributQuand l'utiliserExemple
aria-labelQuand aucun texte visible ne peut servir de label<button aria-label="Fermer">×</button>
aria-labelledbyQuand un texte visible existant peut servir de label<div aria-labelledby="titre-section">...</div>
aria-describedbyPour une description complémentaire (aide, format attendu)<input aria-describedby="aide-mdp" />

aria-labelledby est prioritaire sur aria-label et sur le contenu textuel de l'élément. Si les deux sont présents, seul aria-labelledby est lu par les lecteurs d'écran.

Erreurs ARIA les plus courantes

Voici les erreurs que l'on retrouve le plus souvent lors des audits d'accessibilité :

  1. Utiliser ARIA au lieu du HTML natif
    <!-- MAUVAIS -->
    <div role="button" tabindex="0" onclick="submit()">Valider</div>
    
    <!-- BON -->
    <button type="submit">Valider</button>
  2. aria-hidden sur un élément focusable
    <!-- MAUVAIS : le lien est invisible pour les lecteurs d'écran
         mais reste focusable au clavier -->
    <a href="/page" aria-hidden="true">Lien masqué</a>
    
    <!-- BON : si l'élément doit être masqué, empêcher aussi le focus -->
    <a href="/page" aria-hidden="true" tabindex="-1">Lien masqué</a>
  3. aria-label redondant avec le texte visible
    <!-- MAUVAIS : double annonce par le lecteur d'écran -->
    <button aria-label="Envoyer le formulaire">Envoyer le formulaire</button>
    
    <!-- BON : le texte visible suffit -->
    <button>Envoyer le formulaire</button>
  4. Oublier de mettre à jour les états ARIA
    <!-- MAUVAIS : aria-expanded n'est jamais mis à jour -->
    <button aria-expanded="false" @click="toggle">Menu</button>
    
    <!-- BON : l'état est synchronisé avec l'interface -->
    <button :aria-expanded="isOpen.toString()" @click="toggle">Menu</button>
  5. Abuser d'aria-live — Trop de zones live rendent la navigation insupportable. Limitez-vous aux zones vraiment nécessaires (messages d'erreur, confirmations d'action, mises à jour de compteur).
  6. Rôles ARIA sans le comportement clavier attendu — Ajouter role="tab" sans implémenter la navigation par flèches, ou role="dialog" sans piéger le focus.

ARIA et les formulaires

ARIA joue un rôle crucial dans l'accessibilité des formulaires. Voici les attributs les plus utilisés :

<!-- Formulaire avec ARIA complet -->
<form aria-label="Formulaire d'inscription">
  <div>
    <label for="email">Email *</label>
    <input
      id="email"
      type="email"
      aria-required="true"
      aria-invalid="false"
      aria-describedby="aide-email"
      autocomplete="email"
    />
    <p id="aide-email">Exemple : nom@domaine.fr</p>
  </div>

  <div>
    <label for="mdp">Mot de passe *</label>
    <input
      id="mdp"
      type="password"
      aria-required="true"
      aria-invalid="true"
      aria-describedby="erreur-mdp aide-mdp"
      autocomplete="new-password"
    />
    <p id="erreur-mdp" role="alert">
      Le mot de passe doit contenir au moins 8 caractères.
    </p>
    <p id="aide-mdp">
      Minimum 8 caractères, 1 majuscule, 1 chiffre.
    </p>
  </div>

  <fieldset>
    <legend>Notifications</legend>
    <label>
      <input type="checkbox" name="newsletter" />
      Recevoir la newsletter
    </label>
    <label>
      <input type="checkbox" name="alertes" />
      Recevoir les alertes
    </label>
  </fieldset>

  <button type="submit">Créer mon compte</button>
</form>

Tester vos implémentations ARIA

La meilleure façon de valider vos implémentations ARIA est de les tester avec de vrais lecteurs d'écran :

  • NVDA + Firefox — Combinaison de référence pour les tests sous Windows (gratuit).
  • VoiceOver + Safari — Combinaison de référence pour macOS et iOS.
  • TalkBack + Chrome — Combinaison de référence pour Android.
  • Chrome DevTools — L'onglet « Accessibility » affiche l'arbre d'accessibilité et les propriétés ARIA de chaque élément.
  • aXe DevTools — Détecte de nombreuses erreurs ARIA courantes automatiquement.

Utilisez également RGAA Test pour détecter automatiquement les erreurs ARIA les plus courantes sur l'ensemble de votre site.

Référence rapide des attributs ARIA

AttributUsageValeurs
aria-labelNom accessible invisibleTexte libre
aria-labelledbyNom accessible via un autre élémentID(s) d'élément(s)
aria-describedbyDescription complémentaireID(s) d'élément(s)
aria-expandedÉtat ouvert/fermétrue / false
aria-hiddenMasquer aux technologies d'assistancetrue / false
aria-liveZone de contenu dynamiquepolite / assertive / off
aria-requiredChamp obligatoiretrue / false
aria-invalidSaisie invalidetrue / false / grammar / spelling
aria-currentÉlément courantpage / step / location / date / time / true
aria-controlsÉlément contrôléID d'élément

Résumé : ARIA est un outil puissant mais à manier avec précaution. Respectez la règle numéro un : utilisez toujours le HTML sémantique en priorité. N'ajoutez ARIA que lorsque le HTML natif ne peut pas transmettre l'information nécessaire aux technologies d'assistance. Et surtout, testez toujours avec un lecteur d'écran pour valider que vos implémentations fonctionnent réellement.

Testez la conformité de votre site

Scannez votre site et obtenez un rapport détaillé avec recommandations IA.

Scanner mon site - 15€