Saltar al contenido principal

Formularios

Etiquetas

Los controles de un formulario deben estar identificados con su correspondiente etiqueta.

Etiqueta visible

Utiliza el elemento label para asociar la etiqueta con el control del formulario.

Ejemplo
HTML
<label for="nombre">Nombre</label>
<input type="text" name="nombre" id="nombre">

Nota: La etiqueta y el control del formulario se asocian con los atributos for y id usando el mismo valor.

Etiqueta oculta

Aunque la recomendación es incluir siempre la etiqueta, existen casos donde no es necesario porque la función del campo es explícita visualmente. En estos casos podemos ocultar la etiqueta o no incluirla, pero debemos ofrecer una alternativa para las tecnologías asistivas.

Técnica 1: ocultar el texto de label

En este ejemplo, la función del elemento del formulario se intuye claramente con el texto del botón y, por tanto, podemos ocultar visualmente la etiqueta.

Ejemplo
HTML
<label for="buscar" class="screen-reader">Buscar: </label>
<input type="text" name="buscar" id="buscar">
<button type="submit">Buscar</button>

Técnica 2: usar aria-label

Otra opción es, no incluir el elemento label, y utilizar el atributo aria-label en el control del formulario.

HTML
<input type="text" name="buscar" aria-label="Buscar">
<button type="submit" value="Submit">Buscar</button>

Botones

Si usamos el elemento button la etiqueta es el texto del contenido.

HTML
<button type="submit">Enviar</button>

Y si usamos el elemento input la etiqueta se incluye en el atributo value.

HTML
<input type="submit" value="Enviar">

Etiquetas consistentes

Los elementos que tienen una misma función deben estar identificados con una misma etiqueta.

Por ejemplo, si un campo de contraseña tiene la etiqueta “Contraseña”, si aparece en otra parte del sitio, debe tener la misma etiqueta, y no otra como “Clave” o “Password”.

Agrupar controles

Agrupar semánticamente los controles facilita la comprensión y la interacción con el formulario.

Agrupar controles con el elemento fieldset

El elemento fieldset crea un contenedor para agrupar campos relacionados. Lo acompaña el elemento legend que identifica o describe al grupo.

Ejemplo
Datos de envío



...
HTML
<fieldset>
    <legend>Datos de envío</legend>
    <label for="nombre">Nombre:</label><br>
    <input type="text" name="nombre" id="nombre">
    <label for="calle">Calle:</label><br>
    <input type="text" name="calle" id="calle">
    <label for="num">Número:</label><br>
    <input type="text" name="num" id="num">
    <label for="ciudad">Ciudad:</label><br>
    <input type="text" name="ciudad" id="ciudad">
    ...
</fieldset>

Nota: Los controles de tipo radio y checkbox deberían agruparse siempre para ser tratados semánticamente como un único grupo.

Agrupar controles con ARIA

Una alternativa a fieldsety legend para agrupar controles relacionados es utilizar ARIA. Para ello agrupamos los controles con role=group y etiquetamos el grupo usando aria-labelledby junto con un id.

Ejemplo

Datos de envío





...
HTML
<div role="group" aria-labelledby="datos-envio">
    <h3 id="datos-envio">Datos de envío</h3>

    <label for="nombre">Nombre:</label><br>
    <input type="text" name="nombre" id="nombre">
    <label for="calle">Calle:</label><br>
    <input type="text" name="calle" id="calle">
    <label for="num">Número:</label><br>
    <input type="text" name="num" id="num">
    <label for="ciudad">Ciudad:</label><br>
    <input type="text" name="ciudad" id="ciudad">
    ...

</div>

Agrupar elementos dentro de un select

El elemento optgroup permite agrupar una serie de elementos dentro de un control de tipo select. El atributo label proporciona una etiqueta para el grupo.

Ejemplo
Accesibilidad Web
HTML
<select>
    <optgroup label="Contenido">
        <option value="1.1">Texto</option>
        <option value="1.2">Imágenes</option>
        <option value="1.3">Audio y vídeo</option>
        <option value="1.3">Tablas</option>
        <option value="1.3">Formularios</option>
    </optgroup>
        <optgroup label="Diseño">
        <option value="2.1">Diseño adaptable</option>
        <option value="2.1">Contraste</option>
        <option value="2.1">Color</option>
    </optgroup>
    ...
</select>

Instrucciones

Proporciona instrucciones que ayuden a los usuarios a rellenar los formularios.

Instrucciones generales

Son instrucciones que afectan a todo el formulario. Pueden indicar qué entradas son obligatorias, el formato de datos o cualquier otra información adicional.

Ejemplo
  • Todos los campos marcados como "obligatorio" deben ser rellenados.
  • Las fechas deben escribirse con el formato dd/mm/aaaa (ejemplo: 22/01/1982).

Nota: El texto de las instrucciones debe incluirse antes de la etiqueta <form>. Esto se debe a que algunos lectores de pantalla no leen los textos que no formen parte de elementos de formulario, cuando están dentro de <form>.

Instrucciones en línea

Son instrucciones relevantes que se incluyen junto al control del formulario.

Método 1: instrucciones dentro de label

La forma más simple de proporcionar instrucciones en línea es incluirlas dentro de la etiqueta label.

Ejemplo
HTML
<label for="email">Email (obligatorio): </label>
<input type="email" name="email" id="email">

Método 2: instrucciones usando ARIA

Se asocian las instrucciones con el control de formulario usando el atributo aria-labelledby.

Ejemplo
(obligatorio)
HTML
<label for="email">Email: </label>
<input type="email" name="email" id="email" aria-labelledby="emailLabel">
<span id="emailLabel"> (obligatorio)</span>

Método 3: instrucciones usando placeholder

El atributo placeholder nos permite incluir un texto dentro del campo de formulario que desaparece al empezar a escribir o, en algunos navegadores, al enfocar el campo.

Ejemplo

Este atributo es muy práctico pero presenta algunos problemas de accesibilidad:

  • Los lectores de pantalla no tratan placeholder como una etiqueta.
  • Al desaparecer la información, el usuario puede que no recuerde las instrucciones proporcionadas.
  • Los navegadores suelen usar un tono más claro para el texto que no suele cumplir los requisitos mínimos de contraste. Esto se puede solucionar con CSS usando el pseudo-elemento ::placeholder.

Aviso: El atributo placeholder no debería sustituir a la etiqueta del control de formulario. Para evitar información redundante se pueden usar etiquetas con texto oculto.

Validación

Antes de enviar los datos de un formulario se deben validar y, si existe algún error, notificarlo al usuario.

Validar campos obligatorios

Los campos obligatorios deben identificarse claramente usando etiquetas.

A nivel de código, podemos indicar que el campo es obligatorio añadiendo el atributo required. Si el campo queda vacío, el navegador presentará un mensaje de aviso indicando que debe completarse, al pulsar el botón de envío.

Ejemplo
HTML
<label for="nombre">Nombre (obligatorio): </label>
<input type="text" name="nombre" id="nombre" required>

Nota: Existe un atributo ARIA para indicar que un control es obligatorio: aria-required. En teoría no es necesario si ya existe el atributo required.

Validar tipos de datos

HTML5 proporciona atributos para los tipos de datos más comunes de un formulario (email, fecha, url, números etc.). Estos atributos permiten validar el formato de los datos insertados y, en algunos casos, presentan controles específicos.

Ejemplo
Código
<label for="email">Email: </label>
<input type="email" name="email" id="email">

<label for="fecha">Fecha: </label>
<input type="date" name="fecha" id="fecha">

<label for="num">Número: </label>
<input type="number" name="num" id="num" min="0" max="50" step="5" value="0">

Nota: Algunos tipos de datos pueden incluir parámetros adicionales como valores mínimo y máximo, longitud máxima de caracteres o el rango de aumento o disminución de un valor.

Aviso: El tipo de datos date no está soportado en todos los navegadores. Si se utiliza, hay que proporcionar una alternativa para validar las fechas.

Validar patrones de datos

El atributo de HTML5 pattern permite validar los datos de un campo de entrada usando expresiones regulares.

Ejemplo
HTML
<label for="contraseña">Contraseña (debe contener al menos un número o un caracter especial y mínimo 8 caracteres): </label>
<input type="text" name="contrs" id="contrs" pattern="(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n]).*$" required>

En el ejemplo anterior, si la contraseña no cumple los requisitos, el navegador muestra un mensaje indicando que el formato utilizado debe coincidir con el solicitado.

Validación del lado del servidor

Además de la validación en el cliente, también debe realizarse la validación en el servidor. Si el navegador no soporta alguna técnica utilizada o si los datos se modifican antes de enviarlos es fácil que se produzcan errores.

La validación en el servidor se trata además de una medida de seguridad necesaria.

Notificaciones

Una vez enviados los datos del formulario, hay que informar al usuario de forma clara de si todo ha ido bien o de si se ha producido algún error. Para ello podemos usar las siguientes técnicas.

Usar el título de página

Es lo primero que suele leer un lector de pantalla, así el usuario se percata del error de forma inmediata.

HTML
<title>Gracias por enviar tu comentario</title>

<title>Error - Datos incorrectos</title>

Usar el encabezado principal

El encabezado principal suele ser el elemento más visible de la página.

HTML
<h1>Gracias por enviar tu comentario</h1>

<h1>Error - Datos incorrectos</h1>

Lista de errores

Si existe algún error, además de notificarlo en el título de página y en el encabezado principal, hay que presentar una lista detallada de los mismos. Esta lista debe colocarse al principio de la página, antes del formulario.

Ejemplo
HTML
<div role="alert">
  <h4>Hay 2 errores en este formulario</h4>
  <ul>
    <li>
      <a href="#name" id="name_error">
        El campo nombre está vacío; es un campo obligatorio y debe ser rellenado.
      </a>
    </li>
    <li>
      <a href="#password" id="password_error">
        El campo contraseña no tiene el formato correcto; comprueba que tiene mínimo 8 caracteres.
      </a>
    </li>
  </ul>
</div>
HTML
<label for="name">Nombre (obligatorio): </label>
<input type="text" name="name" id="name" required aria-describedby="name_error">

<label for="password">Contraseña (obligatorio, mínimo 8 caracteres): </label>
<input type="password" name="password" id="password" required aria-describedby="password_error">

Nota: En el ejemplo anterior los elementos de la lista están enlazados con el control correspondiente. Además se incluye el atributo ARIA aria-describedby para asociar cada campo del formulario con su mensaje de error.