Normative · ARIA

Stato Stato di regione live

aria-live

Segna una regione i cui aggiornamenti devono essere annunciati dalla tecnologia assistiva senza spostare il focus. Per la maggior parte dei casi si sceglie «polite»; «assertive» è riservato agli aggiornamenti genuinamente urgenti. La regione deve essere presente nel DOM al momento del rendering iniziale.

Quando utilizzarlo

Quando una parte della pagina si aggiorna in modo asincrono e si desidera che gli utenti di screen reader ne siano informati senza interrompere la lettura in corso. I casi tipici sono: riepiloghi di validazione dei form, conteggi dei risultati di ricerca, notifiche toast, messaggi in una chat in streaming e contatori del carrello acquisti.

Il livello di cortesia va scelto con attenzione:

  • aria-live="polite" — attende che l’utente sia inattivo prima di annunciare. Da usare per quasi tutto: messaggi di stato, risultati caricati, elemento aggiunto al carrello.
  • aria-live="assertive" — interrompe l’utente immediatamente. Riservato alle informazioni genuinamente urgenti — sessione in scadenza tra 30 secondi, invio del form fallito, pagamento rifiutato. L’abuso rende la pagina ostile.
  • aria-live="off" (valore predefinito) — nessun annuncio.

I role nativi role="status" (implica polite) e role="alert" (implica assertive) includono aria-live con impostazioni predefinite appropriate. È preferibile usarli quando si adattano alla situazione; si ricorre a aria-live su un contenitore personalizzato solo quando non lo fanno.

Come mantenerla sincronizzata

La regola fondamentale: la live region deve essere presente nel DOM al rendering iniziale. I browser e le tecnologie assistive impostano la «sorveglianza» della regione quando essa appare per la prima volta nell’albero di accessibilità. Se si crea la regione e vi si inietta il contenuto nello stesso ciclo JavaScript, l’annuncio viene spesso perso.

Il pattern corretto è:

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

Il contenitore vuoto viene reso al caricamento della pagina. In seguito, il testo viene scritto al suo interno tramite JavaScript. Lo screen reader annuncia la modifica.

Ulteriori regole:

  • L’aggiornamento avviene impostando textContent; sostituire l’intero HTML esterno della regione può interrompere la sorveglianza.
  • Per ripetere gli annunci è necessaria una variazione del contenuto — scrivere due volte la stessa stringa spesso non produce un secondo annuncio. Si aggiunga un contatore, un timestamp o si svuoti brevemente la regione.
  • Si abbini aria-busy="true" durante aggiornamenti a più fasi per evitare annunci parziali.
  • Si abbini aria-atomic per controllare se viene annunciata la differenza o l’intera regione.

Errori comuni

  • Creare la live region nello stesso ciclo in cui si inserisce il contenuto — nessun annuncio.
  • Usare aria-live="assertive" per tutto. Gli utenti disattivano l’audio della scheda.
  • Impostare aria-live su un controllo dotato di focus. Le live region sono per gli aggiornamenti di stato, non per i widget interattivi.
  • Nascondere la live region con display: none. Le regioni nascoste tramite CSS sono escluse anche dall’albero di accessibilità e non producono annunci; si utilizzi invece la tecnica visually-hidden (clip / sr-only).
  • Inserire contenuti molto lunghi (paragrafi di testo) in una live region tutto in una volta — l’utente non riesce a scorrere.
  • Dimenticare di svuotare la regione dopo che il messaggio è stato letto, così i successivi aggiornamenti identici non producono nulla.

Esempio

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

<!-- Sempre presente dal rendering iniziale -->
<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>