Normes · ARIA

État État de région dynamique

aria-live

Marque une région dont les mises à jour doivent être annoncées par la technologie d'assistance sans déplacer le focus. Choisissez "polite" dans la plupart des cas, "assertive" pour les mises à jour réellement urgentes. La région doit être dans le DOM dès le rendu initial.

Quand l’utiliser

Lorsqu’une partie de la page se met à jour de manière asynchrone et que vous souhaitez que les utilisateurs de lecteurs d’écran en soient informés sans interrompre leur lecture en cours. Les résumés de validation de formulaires, les comptages de résultats de recherche, les notifications toast, les messages de flux de discussion et les compteurs de panier d’achat sont les cas typiques.

Choisissez le niveau de politesse délibérément :

  • aria-live="polite" — attend que l’utilisateur soit inactif avant d’annoncer. À utiliser pour presque tout : messages de statut, résultats chargés, article ajouté au panier.
  • aria-live="assertive" — interrompt l’utilisateur immédiatement. À réserver aux informations réellement urgentes — session expirant dans 30 secondes, échec de soumission de formulaire, paiement refusé. Un usage excessif rend la page hostile.
  • aria-live="off" (par défaut) — aucune annonce.

Les rôles natifs role="status" (implicitement polite) et role="alert" (implicitement assertive) regroupent aria-live avec des valeurs par défaut sensées. Préférez-les quand ils conviennent ; recourez à aria-live sur un conteneur personnalisé dans le cas contraire.

Comment maintenir la synchronisation

La règle cruciale : la région live doit être dans le DOM dès le rendu initial. Les navigateurs et les technologies d’assistance configurent la « surveillance » de la région à sa première apparition dans l’arbre d’accessibilité. Si vous créez la région et injectez du contenu dans la même boucle JavaScript, l’annonce est souvent manquée.

Le modèle est le suivant :

<div id="status" aria-live="polite"></div>

Affichez le conteneur vide au chargement de la page. Ensuite, écrivez du texte dedans avec JavaScript. Le lecteur d’écran annonce le changement.

Autres règles :

  • Mettez à jour en définissant textContent ; remplacer l’intégralité du HTML externe de la région peut casser la surveillance.
  • Les annonces répétées nécessitent un changement de contenu — écrire la même chaîne deux fois ne produit souvent pas de seconde annonce. Ajoutez un compteur, un horodatage, ou effacez brièvement la région.
  • Associez aria-busy="true" lors de mises à jour en plusieurs étapes pour éviter les annonces partielles.
  • Associez aria-atomic pour contrôler si le différentiel ou l’intégralité de la région est annoncé.

Erreurs courantes

  • Créer la région live dans la même boucle que le contenu — aucune annonce.
  • Utiliser aria-live="assertive" pour tout. Les utilisateurs mettent l’onglet en sourdine.
  • Définir aria-live sur un contrôle focalisable. Les régions live sont destinées aux mises à jour de statut, pas aux composants interactifs.
  • Masquer la région live avec display: none. Les régions masquées par CSS sont également masquées dans l’arbre d’accessibilité et ne produisent aucune annonce ; utilisez plutôt la technique visually-hidden (clip / sr-only).
  • Injecter du contenu très long (plusieurs paragraphes) dans une région live d’un coup — l’utilisateur ne peut pas le parcourir.
  • Oublier d’effacer la région après que le message a été lu, de sorte que les mises à jour identiques suivantes ne produisent rien.

Exemple

<form>
  <label for="zip">ZIP code</label>
  <input id="zip" name="zip" />
  <button type="submit">Look up</button>
</form>

<!-- Toujours présent dès le rendu initial -->
<div id="lookup-status" aria-live="polite" class="sr-only"></div>

<script>
  document.querySelector('form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const status = document.getElementById('lookup-status');
    status.textContent = 'Looking up location…';
    const place = await lookup(document.getElementById('zip').value);
    status.textContent = `Location: ${place}`;
  });
</script>