Técnica ARIA WCAG 2.2
ARIA19Anunciar los errores de un formulario con role="alert" o aria-live
Nombre oficial en el W3C: Usar la función (role) alert de ARIA o regiones activas para identificar errores
En pocas palabras
Cuando un formulario muestra un error sin recargar la página, el lector de pantalla no se entera solo. Si el mensaje se escribe en una región activa (una zona marcada con role="alert" o aria-live), se lee en voz alta al instante. Esa zona debe existir en la página desde el principio.
Por qué es importante
Una persona ciega pulsa «Enviar» y el foco se queda en el botón. El mensaje de error aparece en pantalla, pero ella no lo oye. Cree que todo ha ido bien.
Una región activa hace que el lector de pantalla lea el mensaje sin mover el foco. Así la persona sabe que hay un error y puede corregirlo.
Cómo se hace
- Coloque en el HTML inicial un contenedor vacío con
role="alert", que equivale aaria-live="assertive". - Añádale
aria-atomic="true"para que se lea el mensaje completo. VoiceOver en iPhone y iPad lo necesita para avisar a partir del segundo envío. - Al detectar el error, escriba el texto dentro de ese contenedor con JavaScript.
- En cada nuevo envío, vacíe el contenedor antes de escribir el mensaje nuevo.
- Reserve
role="alert"para errores y avisos urgentes. Para mensajes de éxito, userole="status".
Ejemplo práctico
Formulario de suscripción al boletín de una tienda online. Valida el correo con JavaScript, sin recargar la página. El mensaje de error aparece junto al botón, pero el foco no se mueve hasta él.
Así no: Error escrito en un párrafo sin región activa
El mensaje se ve en rojo, pero se escribe en un <p> normal. El lector de pantalla no anuncia nada. La persona sigue en el botón sin saber que el envío ha fallado. Para notarlo, active NVDA o VoiceOver y envíe el formulario vacío.

La demostración contiene, a propósito, el error de accesibilidad que se explica.
Ver el código del ejemplo incorrecto
<form id="boletin" action="#" novalidate>
<label for="correo">Correo electrónico</label>
<input type="email" id="correo" autocomplete="email">
<button>Suscribirme</button>
<p id="error" class="error"></p>
</form>
<style>.error { color: #b00020; font-weight: bold; }</style>
<script>
document.getElementById('boletin').addEventListener('submit', function (e) {
e.preventDefault();
var campo = document.getElementById('correo');
var valido = campo.value && campo.validity.valid;
document.getElementById('error').textContent = valido ? '' :
'Error: escriba un correo electrónico válido, por ejemplo nombre@dominio.es.';
});
</script>Así sí: Contenedor con role="alert" presente desde la carga
El mismo párrafo lleva role="alert" y aria-atomic="true" desde que se carga la página. Así, el texto que se escribe en él se anuncia al momento. En cada envío se vacía el contenedor y se vuelve a escribir el mensaje. De este modo también se anuncia si el error se repite.
Pruébelo aquí:
Ver el código del ejemplo correcto
<form id="boletin" action="#" novalidate>
<label for="correo">Correo electrónico</label>
<input type="email" id="correo" autocomplete="email">
<button>Suscribirme</button>
<p id="error" class="error" role="alert" aria-atomic="true"></p>
</form>
<style>.error { color: #b00020; font-weight: bold; }</style>
<script>
document.getElementById('boletin').addEventListener('submit', function (e) {
e.preventDefault();
var campo = document.getElementById('correo'), caja = document.getElementById('error');
var valido = campo.value && campo.validity.valid;
caja.textContent = '';
if (!valido) setTimeout(function () {
caja.textContent = 'Error: escriba un correo electrónico válido, por ejemplo nombre@dominio.es.';
}, 100);
});
</script>Cómo comprobarlo
Errores frecuentes en auditorías
- Crear el contenedor con role="alert" en el mismo momento del error. Muchos lectores de pantalla no lo anuncian.
- Escribir el mismo mensaje que ya había sin vaciar antes el contenedor. El segundo error no se anuncia.
- Poner role="alert" en todo el formulario o en un contenedor grande. Se lee entero cada vez que algo cambia.
- Usar role="alert" en mensajes informativos o de éxito. No son urgentes y deben ir en role="status".
Ver el texto completo del W3C (traducción al español)
Esta es una traducción no oficial al español de la técnica ARIA19 de Techniques for WCAG 2.2, del W3C. Puede contener errores. El único documento oficial y normativo es la versión original en inglés, publicada en el sitio web del W3C.
Aplicabilidad
Tecnologías que admiten Accessible Rich Internet Applications (WAI-ARIA).
Descripción
El propósito de esta técnica es notificar a las tecnologías de asistencia cuando se produce un error de entrada. El atributo aria-live hace posible que una tecnología de asistencia (como un lector de pantalla) reciba una notificación cuando se inyectan mensajes de error en un contenedor de región activa (live region). El contenido de la región aria-live es leído automáticamente por la tecnología de asistencia, sin que esta tenga que situar el foco en el lugar donde se muestra el texto.
También existen varias funciones (roles) de región activa para casos especiales que pueden usarse en lugar de aplicar directamente las propiedades de región activa.
Ejemplos
Inyectar mensajes de error en un contenedor con role=alert ya presente en el DOM
El siguiente ejemplo usa role=alert, que equivale a usar aria-live=assertive.
En el ejemplo hay un elemento contenedor de mensajes de error vacío con aria-atomic=true y una propiedad aria-live o una función alert, presente en el DOM al cargar la página. El contenedor de errores debe estar presente en el DOM al cargar la página para que la mayoría de los lectores de pantalla lean el mensaje de error. aria-atomic=true es necesario para que VoiceOver en iOS lea los mensajes de error después de más de un envío no válido.
Se usa JavaScript para comprobar si los campos de entrada están vacíos al enviar el formulario y, en ese caso, inyectar los mensajes de error en los contenedores de región activa. Cada vez que se intenta un nuevo envío, los mensajes de error anteriores se eliminan del contenedor y se inyectan los nuevos.
// Get the form element
const form = document.getElementById('signup');
// Listen for when the form is submitted
form.addEventListener('submit', function(event) {
// Stop the form from actually submitting (so we can check it first)
event.preventDefault();
// Get references to the input fields
const firstNameInput = document.getElementById('first');
const lastNameInput = document.getElementById('last');
const emailInput = document.getElementById('email');
// Get the element where we'll show error messages
const errorsContainer = document.getElementById('errors');
// Create an empty array to collect error messages
const errorMessages = [];
// Check if first name is empty
if (firstNameInput.value === '') {
errorMessages.push('<li>Please enter your first name.</li>');
}
// Check if last name is empty
if (lastNameInput.value === '') {
errorMessages.push('<li>Please enter your last name.</li>');
}
// Check if email is empty
if (emailInput.value === '') {
errorMessages.push('<li>Please enter your email address.</li>');
}
// Clear the errors container first
// (This helps screen readers notice when new content appears)
errorsContainer.innerHTML = '';
// Wait 500 milliseconds, then show the errors
setTimeout(function() {
// If there are any errors, wrap them in a list and display them
if (errorMessages.length > 0) {
errorsContainer.innerHTML = '<ul>' + errorMessages.join('') + '</ul>';
}
}, 500);
});
<form name="signup" id="signup">
<p id="errors" role="alert" aria-atomic="true"></p>
<div>
<label for="first">First Name (required)</label>
<input autocomplete="given-name" type="text" name="first" id="first">
</div>
<div>
<label for="last">Last Name (required)</label>
<input autocomplete="family-name" type="text" name="last" id="last">
</div>
<div>
<label for="email">Email (required)</label>
<input autocomplete="email" type="text" name="email" id="email">
</div>
<div>
<input type="submit" name="button" id="button" value="Submit">
</div>
</form>
Ejemplo funcional: Usar role=alert para identificar errores.
Pruebas
Procedimiento
- Determinar que al cargar la página hay presente en el DOM (Document Object Model) un contenedor de errores vacío con el atributo
role=alertoaria-live=assertive. - Provocar el error que hace que el contenido de la región activa aparezca o se actualice.
- Determinar que el mensaje de error se ha inyectado en el contenedor de errores ya presente.
Resultados esperados
- Las comprobaciones n.º 1 y n.º 3 son verdaderas.
Recursos
- WAI-ARIA Authoring Practices Guide (guía de prácticas de autor de WAI-ARIA)
- WAI-ARIA, Supported States and Properties, aria-describedby (estados y propiedades admitidos: aria-describedby)
- WAI-ARIA, The Roles model, alert (modelo de funciones: alert)
Cómo lo comprobamos en ADDAW
En cada auditoría de ADDAW revisamos esta técnica página a página y le entregamos los errores con capturas y la forma de corregirlos.
Basado en la técnica ARIA19 del W3C (WCAG 2.2). Explicación y ejemplos: ADDAW. Traducción no oficial del texto del W3C © W3C, licencia de documentos del W3C. ¿Ha visto un error? Escríbanos.