Addaw, ir a inicio Donar

Lección 4 de 10 · 9 min de lectura · Revisado el 26/10/2026

Validación y mensajes de error

Un formulario que rechaza los datos sin decir cuáles ni por qué es una pared. Quien ve bien localiza el campo en rojo; quien usa lector de pantalla, quien tiene baja visión o daltonismo, o quien simplemente va con prisa, se queda atascado. Tres criterios regulan este momento: 3.3.1 Identificación de errores (A), que exige identificar el campo con error y describir el error en texto; 3.3.3 Sugerencias ante errores (AA), que pide sugerir la corrección cuando se conoce; y 4.1.3 Mensajes de estado (AA), que exige que los mensajes que aparecen sin mover el foco sean anunciados por las tecnologías de apoyo. Esta lección traduce los tres a código.

Qué debe tener un buen mensaje de error

  • Texto, no solo color ni icono. Un borde rojo incumple 3.3.1 por sí solo y, además, 1.4.1 Uso del color.
  • Ubicación: junto al campo, normalmente debajo o encima de él, y visible sin desplazarse.
  • Identificación: qué campo falla («Código postal») y qué pasa («debe tener 5 cifras»).
  • Sugerencia: cómo arreglarlo o un ejemplo válido («Ejemplo: 30001»), siempre que no comprometa la seguridad.
  • Asociación programática con el campo mediante aria-describedby y marcado del estado con aria-invalid="true".
  • Resumen al principio del formulario cuando hay varios errores, con enlaces a cada campo.

Ejemplo

Antes de validar:

<label for="cp">Código postal</label>
<input type="text" id="cp" name="cp" inputmode="numeric"
       autocomplete="postal-code" aria-describedby="cp-ayuda">
<p id="cp-ayuda">5 cifras.</p>
<p id="cp-error" class="error" hidden></p>

Después de detectar el error, JavaScript rellena el mensaje, lo muestra y actualiza los atributos:

<input type="text" id="cp" name="cp" inputmode="numeric"
       autocomplete="postal-code" aria-invalid="true"
       aria-describedby="cp-error cp-ayuda">
<p id="cp-ayuda">5 cifras.</p>
<p id="cp-error" class="error">Error: el código postal debe tener 5 cifras. Has escrito 4.</p>

Al volver al campo, el lector anuncia: «Código postal, cuadro de edición, entrada no válida, Error: el código postal debe tener 5 cifras. Has escrito 4. 5 cifras». El mensaje de error va primero en aria-describedby para que se oiga antes que la ayuda.

Cuándo validar y dónde poner el foco

Hay dos momentos razonables para validar: al salir del campo (evento blur) o al enviar el formulario. La validación mientras se escribe, tecla a tecla, es agresiva: marca como erróneo un correo electrónico incompleto cuando la persona aún está escribiéndolo, y para quien usa lector de pantalla supone una interrupción constante. Si validas al salir del campo, no muevas el foco: solo muestra el mensaje y márcalo con aria-invalid.

Al enviar el formulario con errores, la estrategia más robusta es:

  1. Impedir el envío.
  2. Mostrar un resumen de errores al principio del formulario, dentro de un contenedor con role="alert" o con tabindex="-1" al que se mueve el foco.
  3. Listar cada error como un enlace al campo correspondiente, para que la persona pueda ir directamente.
  4. Marcar cada campo con aria-invalid="true" y su mensaje con aria-describedby.
  5. Actualizar el <title> con el número de errores.
<div id="resumen-errores" tabindex="-1">
  <h2>Hay 2 errores en el formulario</h2>
  <ul>
    <li><a href="#cp">Código postal: debe tener 5 cifras</a></li>
    <li><a href="#email">Correo electrónico: falta la arroba</a></li>
  </ul>
</div>
// Tras la validación fallida
const resumen = document.getElementById('resumen-errores');
resumen.hidden = false;
resumen.focus();

Mover el foco al resumen es la opción más clara cuando hay varios errores. Como el lector lo lee al recibir el foco, no hace falta añadirle además role="alert": combinar ambos puede hacer que se anuncie dos veces. Si solo hay uno, es aceptable mover el foco directamente al campo erróneo. Lo que nunca debe pasar es que el formulario se recargue, el foco vuelva al principio de la página y la persona tenga que buscar a ciegas qué ha fallado.

Mensajes de estado y regiones activas (4.1.3)

Cuando un mensaje aparece sin que el foco se mueva a él (validación al salir del campo, «Guardado correctamente», «3 resultados encontrados», «Quedan 2 intentos»), hay que asegurarse de que el lector de pantalla lo anuncie. Para eso sirven las regiones activas: role="alert" para errores urgentes (interrumpe lo que se esté leyendo) y role="status" para confirmaciones y mensajes informativos (espera a que termine la lectura en curso). Dos reglas que fallan constantemente: el contenedor debe existir en el DOM, vacío, antes de insertar el mensaje, y no conviene tener más de una región activa anunciando a la vez.

Error frecuente

Marcar todos los mensajes de error inline con role="alert" y mostrarlos a la vez al enviar. El lector de pantalla recibe seis anuncios simultáneos que se pisan y la persona no entiende ninguno. Usa una sola región activa para el resumen y deja los mensajes inline asociados con aria-describedby, que se leerán al llegar a cada campo.

No depender solo de la validación nativa

El atributo required y los type específicos activan la validación del navegador, que muestra una burbuja junto al campo. Esa burbuja desaparece a los pocos segundos, no se puede ampliar, no siempre la leen los lectores de pantalla y su texto no es personalizable en todos los navegadores. Puedes aprovechar la API de validación (checkValidity(), validationMessage) para la lógica, pero muestra los mensajes con tu propio marcado. Si usas novalidate en el <form> para desactivar las burbujas, conserva required: el estado «obligatorio» sigue siendo programático y no hace falta añadir aria-required.

Prevención de errores

El criterio 3.3.4 Prevención de errores (legales, financieros, de datos) (AA) exige que, en operaciones con consecuencias (pagos, firma de solicitudes, borrado de datos), la persona pueda revisar y corregir antes de confirmar, o que la operación sea reversible, o que se compruebe la información. En la práctica: una pantalla de resumen antes de «Confirmar y pagar», un botón de «Deshacer» tras borrar, o la posibilidad de anular un trámite durante un plazo. Y el 3.3.6 Prevención de errores (todos) (AAA) lo extiende a cualquier envío.

Punto clave

Un error bien comunicado dice qué campo, qué falla y cómo arreglarlo, en texto, junto al campo, asociado con aria-describedby, con aria-invalid="true" y, cuando hay varios, con un resumen enlazado que recibe el foco.

Resumen

  • 3.3.1 exige identificar el campo y describir el error en texto; el color o el icono solos no bastan.
  • 3.3.3 pide sugerir la corrección: formato esperado, ejemplo válido o valor esperado.
  • Asocia el mensaje con aria-describedby y marca el campo con aria-invalid="true".
  • Con varios errores, muestra un resumen enlazado y mueve el foco a él; evita múltiples regiones activas simultáneas.
  • En operaciones con consecuencias, ofrece revisión, reversión o comprobación (3.3.4).

Comprueba lo que has aprendido

Esta lección se puede leer libremente. Para hacer su test de 3 preguntas, los ejercicios prácticos con páginas reales, guardar tu avance y optar al examen y al certificado, matricúlate en el curso.