Cómo hacer que tus formularios sean accesibles: etiquetas, errores y validación

Casi la mitad de todas las páginas de inicio de sitios web tienen etiquetas de campos de formulario ausentes, uno de los errores de accesibilidad más comunes y más fáciles de corregir en la web. Esta guía acompaña a propietarios de sitios web, desarrolladores y responsables de cumplimiento a través de las técnicas exactas necesarias para hacer que los formularios funcionen para todas las personas: etiquetado adecuado, mensajes de error significativos y patrones de validación inclusivos.

Según WebAIM, el 48.6% de las páginas de inicio de sitios web tienen etiquetas de entrada de formulario faltantes, lo que convierte a las entradas sin etiqueta en una de las fallas de accesibilidad individuales más comunes en toda la web. Piensa en lo que eso significa en la práctica: una persona usuaria de lector de pantalla llega a tu formulario de contacto, presiona Tab para moverse por los campos y no escucha más que "edit text" una y otra vez. Los lectores de pantalla anuncian las etiquetas de los campos de formulario; sin ellas, las personas usuarias escuchan "edit text" sin contexto y no saben qué información deben ingresar. Los formularios suelen ser la parte más crítica para el negocio de un sitio web — flujos de pago, pantallas de registro, páginas de contacto, solicitudes de soporte — y, sin embargo, siguen siendo de las experiencias más constantemente rotas para las personas que usan tecnología de asistencia.

Por qué la accesibilidad de formularios importa más de lo que crees

Teniendo en cuenta que 1 de cada 4 personas adultas en EE. UU. vive con una discapacidad, la validación accesible de formularios no es opcional; es esencial. Esa población incluye a personas ciegas o con baja visión, personas con discapacidades motoras que dependen de la navegación por teclado, personas con discapacidades cognitivas que necesitan instrucciones claras y personas que usan software de control por voz para completar formularios. Cada campo sin etiqueta, cada mensaje de error vago y cada patrón de validación que depende únicamente del color es una puerta que se cierra silenciosamente frente a una parte significativa de tu audiencia.

La mayoría de las personas usuarias con discapacidad se encuentran con errores al enviar información y no reciben instrucciones claras sobre cómo corregirlos, lo que les deja dos opciones: abandonar el intento y buscar un formulario más accesible, o pedir ayuda a otra persona; ninguna de las dos es una experiencia ideal. Desde la perspectiva del negocio, los formularios accesibles mejoran la experiencia de usuario, reducen las tasas de abandono y cumplen con los requisitos legales. Desde la perspectiva del cumplimiento normativo, WCAG 1.3.1 (Información y relaciones) y 4.1.2 (Nombre, función, valor) son requisitos de Nivel A que existen desde el lanzamiento de WCAG 2.0 en 2008. No se trata de casos extremos ni de técnicas avanzadas: son las expectativas fundamentales del estándar.

Según el informe WebAIM Million, las etiquetas de formulario faltantes se sitúan de forma constante entre los principales errores de accesibilidad en la web, y la investigación sobre fallos de implementación muestra por qué: las organizaciones se centran en soluciones complejas mientras ignoran patrones básicos que permitirían a las personas con discapacidad usar realmente sus servicios. La buena noticia es que solucionar la mayoría de estos problemas no requiere nada exótico, solo HTML deliberado e informado.

Los criterios de éxito de WCAG que rigen los formularios

Antes de profundizar en la implementación, ayuda saber qué criterios de éxito específicos de WCAG se aplican a los formularios. Las Pautas de Accesibilidad para el Contenido Web (WCAG) describen cuatro principios clave — perceptible, operable, comprensible y robusto (POUR) — que sirven como columna vertebral para sistemas de validación inclusivos. Dentro de ese marco, varios criterios de éxito se refieren directamente al diseño de formularios.

Los criterios más relevantes incluyen: 1.3.1 Información y relaciones (Nivel A), que exige que la información, la estructura y las relaciones transmitidas mediante la presentación puedan determinarse de forma programática; 2.4.6 Encabezados y etiquetas (Nivel AA), que establece que los encabezados y las etiquetas describen el tema o propósito; 3.3.2 Etiquetas o instrucciones (Nivel A), que exige que se proporcionen etiquetas o instrucciones cuando el contenido requiera la entrada de la persona usuaria; y 4.1.2 Nombre, función, valor (Nivel A), que exige que, para todos los componentes de la interfaz de usuario, el nombre y la función puedan determinarse de forma programática.

Al cumplir con las pautas WCAG 3.3.1 a 3.3.4, que abarcan la identificación de errores, instrucciones, sugerencias y prevención, creas formularios más fáciles e intuitivos para todas las personas usuarias. No son obstáculos arbitrarios: cada criterio refleja una necesidad real de las personas usuarias. Entender el "por qué" detrás de cada regla facilita mucho implementarla correctamente y tomar decisiones acertadas en casos límite.

Hacer bien las etiquetas: la base de los formularios accesibles

Una etiqueta no es solo una pista visual. Es la conexión programática entre una descripción textual y un control de formulario, y es el mecanismo principal mediante el cual las tecnologías de asistencia identifican para qué sirve un campo. La forma más robusta de crear esta conexión es con el elemento HTML <label> y su atributo for, apuntando al id de la entrada correspondiente.

<!-- Incorrecto: el placeholder por sí solo no es una etiqueta accesible -->
<input type='email' placeholder='Email address'>

<!-- Correcto: etiqueta explícita asociada mediante for/id -->
<label for='email'>Email address</label>
<input type='email' id='email' name='email'>

Las etiquetas siempre deben ser visibles, no solo placeholders. Los placeholders desaparecen cuando las personas escriben, dejando sin contexto. Esta es una distinción críticamente importante. El texto de placeholder nunca se diseñó para servir como etiqueta; desaparece en el momento en que la persona usuaria empieza a escribir, a menudo tiene un contraste de color insuficiente y muchos lectores de pantalla no lo exponen de forma fiable como el nombre accesible del campo. Confiar únicamente en los placeholders falla a las personas usuarias en general, no solo a quienes usan tecnología de asistencia.

Cuando tienes grupos de campos relacionados — como un conjunto de botones de opción (radio buttons) o un bloque de casillas de verificación — el patrón correcto es <fieldset> y <legend>. Agrupa opciones relacionadas como casillas de verificación y botones de opción con fieldsets y legends para que los formularios complejos sean más fáciles de entender.

<fieldset>
  <legend>Preferred contact method</legend>

  <input type='radio' id='contact-email' name='contact' value='email'>
  <label for='contact-email'>Email</label>

  <input type='radio' id='contact-phone' name='contact' value='phone'>
  <label for='contact-phone'>Phone</label>
</fieldset>

En situaciones en las que una etiqueta visible sería visualmente redundante — por ejemplo, un único campo de búsqueda junto a un botón Search claramente etiquetado — puedes usar aria-label o aria-labelledby para proporcionar un nombre accesible sin mostrar texto visible. Sin embargo, úsalo con moderación. Las personas que usan lectores de pantalla pueden identificar y comprender los controles de formulario más fácilmente porque están asociados con etiquetas, fieldsets y otros elementos estructurales, y las etiquetas visibles benefician a todo el mundo, incluidas las personas videntes con discapacidades cognitivas, las personas que hacen zoom al 400% y cualquiera que haya perdido momentáneamente su ubicación en un formulario largo.

Además, los campos obligatorios deben indicarse visual y programáticamente, usando el atributo required o aria-required. Un asterisco rojo por sí solo no es suficiente: incluye una breve nota como "Los campos marcados con * son obligatorios" en la parte superior del formulario y asegúrate de que el atributo required esté en el marcado para que las tecnologías de asistencia puedan anunciar el campo como obligatorio cuando la persona usuaria se enfoque en él.

Escribir mensajes de error que realmente ayuden

Los mensajes de error son donde la mayoría de los formularios fallan a las personas usuarias de una segunda manera, acumulativa. Después de que una persona usuaria envía un formulario que activa errores de validación, necesita saber tres cosas: que se produjo un error, qué campo lo causó y qué debe hacer para solucionarlo. La mayoría de los errores de formulario responden solo a la primera de estas preguntas, y aun así, de forma deficiente.

Los mensajes de error vagos como "Invalid input" o "Error" no indican a las personas usuarias qué salió mal ni cómo corregirlo. Cada mensaje de error debe identificar el problema específico y sugerir un remedio concreto.

Para garantizar la compatibilidad con los lectores de pantalla, los mensajes de error deben integrarse en el DOM usando atributos ARIA como aria-invalid="true" y aria-describedby, que vinculan los mensajes de error directamente con sus campos de formulario correspondientes. Así es como se ve un estado de error correctamente marcado:

<label for='email'>Email address</label>
<input
  type='email'
  id='email'
  name='email'
  aria-invalid='true'
  aria-describedby='email-error'
>
<span id='email-error' role='alert'>
  Please enter a valid email address, for example: [email protected]
</span>

El atributo aria-invalid="true" indica a un lector de pantalla que el campo tiene actualmente un valor no válido. El atributo aria-describedby apunta al elemento que contiene el mensaje de error, que el lector de pantalla leerá cuando la persona usuaria se enfoque en esa entrada. El role="alert" en el span del error hace que se anuncie inmediatamente cuando se inyecta en el DOM, sin requerir que la persona usuaria navegue hasta él.

En un diseño minimalista, es tentador usar solo un color rojo para expresar que un campo no es válido, pero usar solo el color no es suficiente, como defiende WCAG 1.4.1 Uso del color, porque las personas perciben el color de diferentes maneras y ese color rojo no será percibido por todo el mundo. La solución es complementar el estado de error colorido con un elemento visual adicional — podría ser un ícono, pero incluso eso podría no ser suficiente para entender por qué el campo no es válido, por lo que la solución más inclusiva es mostrar explícitamente un mensaje de texto.

Los mensajes de error específicos son especialmente útiles para personas con desafíos cognitivos, atención reducida o que usan lectores de pantalla, porque una retroalimentación mal redactada puede generar frustración e incluso hacer que abandonen el formulario por completo. Escribe los mensajes de error desde la perspectiva de la persona usuaria: ¿qué necesitaba ingresar y cómo puede corregirlo ahora mismo?

Momento de la validación y gestión del foco

Cuándo validas es tan importante como cómo validas. Si activas errores demasiado pronto — por ejemplo, mientras la persona usuaria aún está escribiendo — corres el riesgo de interrumpir su flujo con quejas prematuras. Si activas errores solo al enviar, podrías dejar a la persona usuaria desplazándose por un formulario largo buscando qué campos necesitan atención. La respuesta adecuada es un enfoque por capas.

Combina retroalimentación en tiempo real para campos críticos, comprobaciones on-blur para entradas con formato y validación al enviar para revisiones de errores exhaustivas. En la práctica, esto significa: valida formatos complejos como contraseñas o direcciones de correo electrónico cuando la persona usuaria abandone el campo (on blur); evita interrumpir con validaciones en línea que se disparan en cada pulsación de tecla; y, al enviar el formulario, realiza una pasada completa y comunica claramente todos los errores a la vez.

Después del envío, dirige automáticamente el foco al primer error para guiar a las personas usuarias de forma eficiente. Si hay varios errores, el patrón más accesible es mover el foco a un resumen en la parte superior del formulario que enumere todos los errores como enlaces que salten a los campos relevantes. Esto significa que la persona usuaria escucha el resumen de errores tan pronto como envía, puede entender el alcance completo de lo que necesita corregir y puede navegar directamente a cada problema.

<!-- Resumen de errores colocado en la parte superior del formulario, enfocado mediante programación -->
<div id='error-summary' role='alert' tabindex='-1'>
  <h2>2 errors found. Please correct the following:</h2>
  <ul>
    <li><a href='#email'>Email address: Please enter a valid email</a></li>
    <li><a href='#phone'>Phone number: Please use the format (555) 555-5555</a></li>
  </ul>
</div>

Asegúrate de que las personas usuarias puedan navegar por los formularios sin ratón, con un orden de tabulación lógico e indicadores de foco visibles. El anillo de foco predeterminado del navegador es una base legal y funcional, pero muchos equipos de diseño lo suprimen con outline: none en su CSS sin proporcionar un reemplazo. Esto hace que el formulario sea prácticamente inutilizable para las personas que solo usan el teclado. Un indicador de foco claro y de alto contraste es obligatorio según WCAG 2.4.7 (Nivel AA) y el más estricto 2.4.11 en WCAG 2.2. Si las directrices de tu marca entran en conflicto con el anillo de foco predeterminado, reemplázalo, no lo elimines.

Proporcionar instrucciones y pistas antes de que ocurran errores

El mejor error de formulario es el que nunca tiene que aparecer. Las instrucciones y pistas bien ubicadas previenen errores desde el principio, lo cual es mejor para todas las personas usuarias. Las entradas obligatorias o las que requieren un formato, valor o longitud específicos deben proporcionar esta información dentro de la etiqueta del elemento o en sus instrucciones asociadas programáticamente.

La etiqueta del campo es la primera instrucción visual sobre qué completar, seguida de una descripción cuando sea necesario. Del mismo modo que las personas videntes pueden ver una descripción, las personas usuarias de lectores de pantalla también deben conocerla, y puedes conectar la descripción con la entrada usando el atributo aria-describedby, que acepta un id que apunta al elemento de descripción, haciendo que el lector de pantalla lea la descripción automáticamente cuando la persona usuaria se enfoque en el campo.

<label for='phone'>Phone number</label>
<input
  type='tel'
  id='phone'
  name='phone'
  aria-describedby='phone-hint'
>
<span id='phone-hint'>Format: (555) 555-5555</span>

Siempre que sea posible, proporciona ejemplos para aclarar las expectativas; por ejemplo, si un campo de fecha requiere el formato MM/DD/YYYY, incluye un ejemplo como "Enter date as 12/25/2024". Para los campos de contraseña, indica los requisitos por adelantado en lugar de revelarlos uno por uno a medida que la persona usuaria viola cada regla. Si es posible, los formularios no deben estar sujetos a un límite de tiempo para permitir que las personas usuarias los completen a su propio ritmo, y si es necesario establecer un límite de tiempo, la persona usuaria debe tener la opción de desactivarlo o ampliarlo.

El atributo autocomplete es otro mecanismo de accesibilidad que se pasa por alto con frecuencia. Establecer valores como autocomplete="email", autocomplete="given-name" o autocomplete="street-address" permite que los navegadores y los gestores de contraseñas completen automáticamente los campos de forma correcta, reduciendo drásticamente la carga para las personas con discapacidades motoras, discapacidades cognitivas o cualquiera que encuentre difícil la escritura repetitiva. WCAG 1.3.5 (Identificar el propósito de la entrada, Nivel AA) exige esto para los campos que recopilan información personal.

Probar la accesibilidad de tus formularios

Conocer las reglas es una cosa; saber si tus formularios realmente las cumplen es otra. Una estrategia de pruebas combinada es el enfoque más fiable. Aunque herramientas como Lighthouse y WAVE pueden ayudar a detectar problemas automáticamente, las pruebas manuales usando solo el teclado y lectores de pantalla son esenciales para detectar problemas de usabilidad en el mundo real.

Para las pruebas con teclado, simplemente desconecta el ratón e intenta completar el formulario. Deberías poder llegar a cada campo, activar cada botón y recibir cada mensaje de error usando solo Tab, Shift+Tab, las teclas de flecha y Enter/Espacio. Si te quedas atascado, eso es un fallo. Para las pruebas con lectores de pantalla, usa NVDA con Firefox en Windows o VoiceOver con Safari en macOS. Los lectores de pantalla se comportan de forma ligeramente diferente entre sí — atajos distintos, anuncios semánticos diferentes y compatibilidad de funciones distinta; por ejemplo, NVDA funciona mejor con Firefox, mientras que VoiceOver funciona mejor con Safari. Probar con al menos dos combinaciones detectará la gama más amplia de problemas.

Herramientas como WAVE y Axe son excelentes para analizar formularios en busca de etiquetas faltantes, atributos ARIA incorrectos y bajo contraste de color. Estas herramientas automatizadas pueden integrarse directamente en tu pipeline de CI/CD para detectar regresiones antes de que lleguen a producción. Sin embargo, dado que las pautas de accesibilidad son matizadas, las herramientas automatizadas solo pueden detectar alrededor del 30% de los problemas de WCAG, por lo que la capa automatizada debe complementarse con revisión manual y, idealmente, pruebas con personas usuarias reales que dependan de la tecnología de asistencia.

Al revisar tu marcado manualmente, hazte las siguientes preguntas para cada campo de formulario: ¿Tiene una etiqueta visible? ¿Esa etiqueta está asociada programáticamente mediante for/id o ARIA? ¿Algún texto de ayuda está conectado con aria-describedby? ¿Cada estado de error establece aria-invalid="true" y hace referencia al mensaje de error mediante aria-describedby? ¿El atributo required está presente en los campos obligatorios? ¿Puedes alcanzar y operar cada elemento interactivo solo con el teclado?

Conclusiones clave

  • Cada entrada necesita una etiqueta programática. Usa <label for='...'> para todos los campos de formulario; nunca confíes solo en el texto de placeholder. Cada campo de formulario necesita una etiqueta programática, sin excepciones; el texto de placeholder no es una etiqueta.
  • Los mensajes de error deben nombrar el problema y sugerir una solución. Los mensajes de error deben identificar el problema y sugerir cómo solucionarlo, y deben asociarse con sus campos usando aria-describedby.
  • Nunca confíes solo en el color. No confíes solo en el color para ninguna indicación de estado; usa texto, íconos y otros indicadores no basados en el color junto con las señales de color.
  • Gestiona el foco después del envío. El error debe identificarse claramente, debe proporcionarse acceso rápido al elemento problemático y la persona usuaria debe poder corregir fácilmente el error y volver a enviar el formulario. Mover el foco a un resumen de errores después de un envío fallido es el estándar de oro.
  • Prueba con herramientas reales, no solo con suposiciones. Mantener los formularios accesibles no es una tarea de una sola vez; requiere pruebas y actualizaciones periódicas para garantizar que sigan siendo conformes y fáciles de usar. Combina el análisis automatizado con la navegación solo con teclado y las pruebas con lectores de pantalla en cada actualización importante del formulario.