aria-live
Marca una región cuyas actualizaciones deben ser anunciadas por la tecnología de apoyo sin desplazar el foco. Se recomienda «polite» para la mayoría de los casos y «assertive» únicamente para actualizaciones genuinamente urgentes. La región debe estar en el DOM desde la carga inicial.
Cuándo utilizarlo
Cuando alguna parte de la página se actualiza de forma asíncrona y se desea que los usuarios de lectores de pantalla estén informados sin interrumpir lo que están leyendo en ese momento. Los casos habituales son: resúmenes de validación de formularios, recuentos de resultados de búsqueda, notificaciones tipo toast, mensajes de chat en tiempo real y contadores del carrito de compra.
El nivel de cortesía debe elegirse deliberadamente:
aria-live="polite"— espera a que el usuario esté inactivo antes de anunciar. Se debe usar para casi todo. Mensajes de estado, resultados cargados, ítem añadido al carrito.aria-live="assertive"— interrumpe al usuario de inmediato. Se reserva para información genuinamente urgente: sesión que expira en 30 segundos, error en el envío del formulario, pago rechazado. El abuso de este valor hace que la página resulte hostil.aria-live="off"(valor predeterminado) — sin anuncios.
Los roles nativos role="status" (implica polite) y role="alert" (implica assertive) incluyen aria-live con valores predeterminados adecuados. Se recomienda usarlos cuando encajen; se debe recurrir a aria-live en un contenedor personalizado cuando no sea así.
Cómo mantenerlo sincronizado
La regla fundamental: la región en tiempo real debe estar en el DOM desde la carga inicial. Los navegadores y las tecnologías de apoyo configuran la «vigilancia» de la región cuando esta aparece por primera vez en el árbol de accesibilidad. Si se crea la región y se inyecta contenido en ella en el mismo ciclo de JavaScript, el anuncio suele perderse.
El patrón correcto es:
<div id="status" aria-live="polite"></div>
Se renderiza el contenedor vacío al cargar la página. Posteriormente, se escribe texto en él mediante JavaScript. El lector de pantalla anuncia el cambio.
Otras reglas:
- Se debe actualizar estableciendo
textContent; reemplazar el HTML externo completo de la región puede interrumpir la vigilancia. - Los anuncios repetidos requieren un cambio de contenido: escribir la misma cadena dos veces a menudo no produce un segundo anuncio. Se puede añadir un contador, una marca de tiempo o limpiar brevemente la región.
- Se debe combinar con
aria-busy="true"durante actualizaciones en varios pasos para evitar anuncios parciales. - Se debe combinar con
aria-atomicpara controlar si se anuncia solo el diferencial o toda la región.
Errores frecuentes
- Crear la región en tiempo real en el mismo ciclo que el contenido: no se produce ningún anuncio.
- Usar
aria-live="assertive"para todo. Los usuarios silencian la pestaña. - Establecer
aria-liveen un control interactivo. Las regiones en tiempo real son para actualizaciones de estado, no para widgets interactivos. - Ocultar la región en tiempo real con
display: none. Las regiones ocultas mediante CSS también quedan ocultas en el árbol de accesibilidad y no producen ningún anuncio; se debe usar la técnica de ocultación visual (clip / sr-only) en su lugar. - Inyectar contenido muy extenso (párrafos de texto) en una región en tiempo real de una sola vez: el usuario no puede recorrerlo.
- Olvidar limpiar la región tras la lectura del mensaje, de modo que las actualizaciones idénticas posteriores no producen ningún anuncio.
Ejemplo
<form>
<label for="zip">Código postal</label>
<input id="zip" name="zip" />
<button type="submit">Buscar</button>
</form>
<!-- Siempre presente desde la carga inicial -->
<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 = 'Buscando ubicación…';
const place = await lookup(document.getElementById('zip').value);
status.textContent = `Ubicación: ${place}`;
});
</script>