Formularios inclusivos: guía con HTML accesible y criterios WCAG

Un formulario deja gente fuera por cosas muy concretas: una etiqueta que el lector de pantalla no encuentra, un campo de género con dos casillas, un error que dice «dato no válido» sin decir cuál. Casi todo se arregla en el HTML, no en el diseño. Estos son los patrones que funcionan y los criterios de las WCAG que los respaldan, incluidos los que entraron con la versión 2.2.

El esqueleto de un campo bien montado

Un campo accesible tiene cuatro piezas: etiqueta asociada, ayuda enlazada, propósito declarado y hueco para el mensaje de error. Así queda un campo de correo completo:

<label for="email">Correo electrónico</label>
<input
  type="email"
  id="email"
  name="email"
  autocomplete="email"
  inputmode="email"
  aria-describedby="email-ayuda email-error"
  required>
<p id="email-ayuda">Lo usamos solo para enviarte la confirmación.</p>
<p id="email-error" role="alert"></p>

El for del label y el id del input tienen que coincidir: ese vínculo es lo que hace que al pulsar sobre el texto se enfoque el campo y que el lector de pantalla lo anuncie. El aria-describedby puede apuntar a varios elementos separados por espacios, así que sirve para encadenar la ayuda y el error en el mismo campo. Y el autocomplete no está ahí por comodidad: el criterio 1.3.5 de las WCAG, de nivel AA, pide declarar el propósito de los campos que recogen datos del propio usuario.

El campo de género, resuelto sin dejar a nadie fuera

La primera pregunta no es cómo plantearlo sino si hace falta. Un campo de género en un formulario de contacto o de descarga no aporta nada y sí obliga a la persona a clasificarse. Si el dato no cambia lo que va a pasar después, fuera.

Cuando sí se necesita, el grupo de opciones va dentro de un fieldset con su legend, que es lo que agrupa los botones de radio de cara a las tecnologías de asistencia:

<fieldset>
  <legend>Género (opcional)</legend>
  <input type="radio" id="g-mujer" name="genero" value="mujer">
  <label for="g-mujer">Mujer</label>

  <input type="radio" id="g-hombre" name="genero" value="hombre">
  <label for="g-hombre">Hombre</label>

  <input type="radio" id="g-nb" name="genero" value="no-binario">
  <label for="g-nb">No binario</label>

  <input type="radio" id="g-otro" name="genero" value="otro">
  <label for="g-otro">Prefiero describirlo</label>
  <label for="g-otro-texto">¿Cómo lo describirías?</label>
  <input type="text" id="g-otro-texto" name="genero_texto">

  <input type="radio" id="g-nd" name="genero" value="no-decir">
  <label for="g-nd">Prefiero no decirlo</label>
</fieldset>

Dos detalles marcan la diferencia. El campo abierto acompaña a su opción en lugar de sustituirla, para que nadie tenga que escribir su identidad en una casilla llamada «otro». Y «prefiero no decirlo» es una respuesta válida por sí misma, distinta de dejarlo en blanco, lo que además permite distinguir en los datos entre quien decide no contestar y quien se saltó el campo.

La edad: fecha, tramo o nada

Si necesitas verificar una mayoría de edad, pide fecha de nacimiento: se calcula sola y no caduca, mientras que una edad escrita a mano queda desfasada al día siguiente. Si lo que buscas es segmentar, un tramo (18-24, 25-34, 35-44) basta y resulta menos invasivo. Y si no vas a usar el dato para nada concreto, no lo pidas: el principio de minimización del RGPD juega justo ahí.

Para la fecha, tres campos separados de día, mes y año suelen funcionar mejor que un selector de calendario, sobre todo cuando hay que retroceder décadas. Cada uno con su label propio y el conjunto dentro de un fieldset.

Los criterios WCAG que tocan a un formulario

Conviene tenerlos a mano con su número, porque son los que aparecen en cualquier auditoría:

  • 1.3.5 Identificar el propósito de la entrada (AA): declarar con autocomplete qué dato del usuario recoge cada campo.
  • 1.4.3 Contraste mínimo (AA): 4,5:1 entre el texto y su fondo, también en etiquetas y textos de ayuda.
  • 1.4.11 Contraste no textual (AA): 3:1 para los bordes de los campos y para los iconos, que es donde más se falla con los grises claros de moda.
  • 2.5.8 Tamaño del objetivo (AA, nuevo en 2.2): al menos 24 por 24 píxeles CSS para cada control, con excepciones como los enlaces dentro de una frase.
  • 3.3.1 Identificación de errores (A) y 3.3.3 Sugerencia ante errores (AA): decir qué campo falla y cómo corregirlo.
  • 3.3.2 Etiquetas o instrucciones (A): cada campo con su etiqueta visible.
  • 3.3.7 Entrada redundante (A, nuevo en 2.2): no volver a pedir un dato que el usuario ya introdujo en el mismo proceso.
  • 3.3.8 Autenticación accesible (AA, nuevo en 2.2): no obligar a resolver pruebas cognitivas, como recordar o transcribir, para iniciar sesión.

Las WCAG 2.2 se publicaron el 5 de octubre de 2023 y añadieron nueve criterios a los de la versión anterior. En sentido contrario, retiraron el 4.1.1 de análisis sintáctico, que quedó obsoleto.

Errores que se entienden

Un mensaje de error tiene que decir qué campo falla, qué pasa y cómo arreglarlo, y tiene que llegar a quien no lo ve en pantalla. El patrón que cumple las dos cosas combina aria-invalid en el campo con un contenedor role="alert" que el lector de pantalla anuncia en cuanto recibe texto:

<input type="text" id="cp" name="cp"
  autocomplete="postal-code"
  aria-describedby="cp-error"
  aria-invalid="true">
<p id="cp-error" role="alert">
  El código postal tiene cinco cifras. Has escrito cuatro.
</p>

La validación conviene lanzarla al salir del campo, no mientras se escribe, porque avisar de que un correo es inválido cuando la persona lleva tres letras es ruido. Y al enviar con errores, el foco debe ir al primero de ellos, no al principio de la página.

Lo que sobra en casi todos los formularios

El placeholder usado como etiqueta desaparece al escribir, deja a la persona sin referencia a mitad del campo y suele venir en un gris que no llega al contraste mínimo. El asterisco sin leyenda obliga a adivinar; es más corto escribir «(opcional)» en los pocos campos que lo sean. Los captchas de descifrar letras chocan de frente con el criterio 3.3.8. Y los formularios de quince campos donde solo se usan cuatro tienen un problema que ninguna etiqueta arregla.

El resto es criterio de producto. Si te interesa el enfoque de prevenir el error antes que señalarlo, lo desarrollamos en diseño de accesibilidad anticipada, y los casos que las WCAG no cubren del todo están en UX para usuarios neurodivergentes. Para los controles que no son un simple input, en componentes accesibles con roles ARIA está el resto del patrón.

Preguntas frecuentes

¿Cómo se plantea el campo de género sin excluir a nadie?

Primero comprobando si hace falta. Si hace falta, con varias opciones dentro de un fieldset, un campo de texto libre asociado a su propia opción y un «prefiero no decirlo» que sea una respuesta válida, no un hueco en blanco.

¿Es mejor pedir la edad o la fecha de nacimiento?

La fecha de nacimiento cuando hay que verificar una edad, porque se calcula sola y no queda desfasada. Un tramo de edad basta cuando el dato solo sirve para segmentar y resulta menos invasivo.

¿Qué contraste necesitan los campos de un formulario?

4,5:1 entre el texto y su fondo según el criterio 1.4.3, y 3:1 para los bordes del campo y los iconos según el 1.4.11. Ese segundo es el que más se incumple con los grises muy claros.

¿Puedo usar el placeholder en lugar de la etiqueta?

No. Desaparece en cuanto se empieza a escribir, deja al usuario sin referencia y choca con el criterio 3.3.2, que pide etiquetas o instrucciones para cada campo.

¿Qué añadieron las WCAG 2.2 para formularios?

Sobre todo el 3.3.7, que evita volver a pedir un dato ya introducido en el mismo proceso, y el 3.3.8, que impide exigir pruebas cognitivas para autenticarse. También el 2.5.8, que fija 24 por 24 píxeles CSS como tamaño mínimo de los controles.

Fuentes

Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.