HTML Forms

Formularios y Validación

Los formularios son la vía por la cual los usuarios envían datos a tu aplicación. Las etiquetas, los tipos de entrada correctos y la validación nativa hacen la mayor parte del trabajo antes de que escribas cualquier línea de JavaScript.

beginner14 min readUpdated 15 sept 2026
signup.html
html
<!-- signup.html -->
<form action="/signup" method="post">
  <label for="email">Email address</label>
  <input id="email" name="email" type="email"
         autocomplete="email" required />

  <label for="password">Password</label>
  <input id="password" name="password" type="password"
         minlength="8" required />

  <button type="submit">Create account</button>
</form>
Contenedor
elemento form
Atributo clave
name
Etiquetado
label con for
Tipos
email, tel, number, date
Validación
Restricciones nativas

Por que importa

Por qué los formularios requieren atención

Usables por todos

Las etiquetas adecuadas, la agrupación y los mensajes de error hacen que los formularios funcionen con lectores de pantalla y teclados.

Validación doble

La validación nativa mejora la experiencia; la validación del servidor protege los datos.

El control correcto

Los tipos de input correctos proporcionan al usuario el teclado adecuado y habilitan comprobaciones integradas.

La imagen completa

Las tres partes de un buen formulario

Una etiqueta clara, el tipo de control adecuado y una validación honesta que ayude en lugar de bloquear.

Estructura

Marcado

form, label, input, fieldset y legend describen los datos que recolectas.

Etiquetado

Claridad

Cada control necesita una etiqueta asociada, tanto visible como programática.

Validación

Protección

Las restricciones nativas más las comprobaciones del servidor mantienen fuera los datos incorrectos.

Formularios de un vistazo

El núcleo de los formularios

form y controles

form envuelve inputs, selects, textareas y botones.

Tipos de Input

email, tel, number, date, url y más cambian el teclado y la validación.

Etiquetas

Asocia cada control con una etiqueta usando for e id.

Fieldsets

Agrupa controles relacionados con fieldset y legend.

Restricciones

required, minlength, pattern, min, max y step.

Errores

Explica qué está mal y cómo solucionarlo, cerca del campo.

Una breve historia

De inputs básicos a restricciones avanzadas

  1. 1993

    Los primeros formularios

    Los formularios HTML permitieron que las páginas enviaran datos a un servidor.

    93
  2. 1999

    Controles de HTML4

    Un conjunto estable de inputs, selects y textareas se convierte en el estándar.

    99
  3. 2011

    Tipos de input de HTML5

    Llegan email, number, date, range y otros con validación nativa.

    11
  4. 2014

    Constraint Validation API

    Los scripts ganan acceso al estado de validez y a mensajes personalizados.

    14
  5. Hoy

    Mejor UX por defecto

    Los tipos y atributos correctos ofrecen teclados móviles, autofill y comprobaciones gratis.

    Hoy

La guia completa

Formularios y Validación: Todo lo que necesitas saber

Por qué los formularios merecen atención

Los formularios son el lugar donde los usuarios te pagan, se registran, realizan búsquedas y envían mensajes. También es donde se concentra la frustración: una etiqueta faltante, un error confuso o un input que abre el teclado incorrecto pueden hacer que pierdas a un usuario en segundos.

La buena noticia es que HTML ya resuelve la mayor parte de esto. Con etiquetas adecuadas, los tipos de input correctos y restricciones nativas, obtienes formularios accesibles, optimizados para móviles y validados antes de escribir una sola línea de JavaScript.

Estructura del formulario

Un formulario envuelve sus controles y declara dónde y cómo enviarlos.

<!-- signup.html -->
<form action="/signup" method="post">
  <label for="email">Email address</label>
  <input id="email" name="email" type="email" autocomplete="email" required />

  <label for="password">Password</label>
  <input id="password" name="password" type="password" minlength="8" required />

  <button type="submit">Create account</button>
</form>
  • action es la URL que recibe los datos.
  • method es get o post.
  • name en cada control es la clave en los datos enviados.
  • type=“submit” activa el envío; un botón simple dentro de un formulario actúa como submit por defecto, así que usa type="button" para otras acciones.

Etiquetas

Cada control necesita una etiqueta. Las etiquetas son anunciadas por los lectores de pantalla, actúan como un área de clic más amplia y permanecen visibles después de que el campo ha sido completado.

<!-- label.html -->
<label for="phone">Phone number</label>
<input id="phone" name="phone" type="tel" autocomplete="tel" />

También puedes envolver el control dentro de la etiqueta, lo que los asocia implícitamente:

<label>
  Subscribe to the newsletter
  <input type="checkbox" name="subscribe" />
</label>

Los placeholders no son etiquetas. Desaparecen una vez que el usuario escribe, suelen tener un contraste deficiente y no se anuncian de manera fiable. Utiliza una etiqueta real y, si es útil, una pista (hint).

Tipos de input

Elegir el type adecuado proporciona a los usuarios el teclado móvil correcto y permite habilitar la validación nativa.

Tipo Uso Beneficio
email Direcciones de correo electrónico Teclado de email, verificación de formato
tel Números de teléfono Teclado numérico
number Valores numéricos Entrada numérica, min/max/step
url Direcciones web Teclado de URL, verificación de formato
date Fechas Selector de fecha
password Secretos Entrada enmascarada
search Campos de búsqueda Teclado de búsqueda, botón de limpiar
file Subidas de archivos Selector de archivos y filtrado por tipo

Utiliza autocomplete con tokens estándar como email, given-name, postal-code y new-password para que los navegadores y los gestores de contraseñas puedan ayudar al usuario.

Agrupación de controles

Agrupa los controles relacionados para que su relación sea clara para todos.

<!-- address.html -->
<fieldset>
  <legend>Shipping address</legend>

  <label for="street">Street</label>
  <input id="street" name="street" autocomplete="address-line1" />

  <label for="city">City</label>
  <input id="city" name="city" autocomplete="address-level2" />
</fieldset>

fieldset y legend agrupan botones de radio y campos relacionados, los cuales los lectores de pantalla anuncian como un conjunto. Para los grupos de radio, utiliza siempre un fieldset con un legend.

Validación nativa

HTML ofrece validación de restricciones (constraint validation) a través de atributos.

<!-- validate.html -->
<input type="email" name="email" required />
<input type="password" name="password" minlength="8" required />
<input type="number" name="age" min="18" max="120" step="1" />
<input type="text" name="handle" pattern="[a-z0-9_]{3,15}" />
<input type="url" name="website" />

El navegador bloquea el envío y muestra un mensaje cuando una restricción falla. Puedes dar estilo a estos estados con CSS:

/* styles.css */
input:invalid { border-color: #dc2626; }
input:valid { border-color: #16a34a; }
input:focus-visible { outline: 2px solid #2563eb; }

Los mensajes nativos son funcionales, pero breves y no están traducidos. Para formularios importantes, proporciona tus propios mensajes claros utilizando la Constraint Validation API:

// validate.js
const email = document.querySelector("#email");

email.addEventListener("invalid", () => {
  email.setCustomValidity("");
  if (email.validity.valueMissing) {
    email.setCustomValidity("Please enter your email address.");
  } else if (email.validity.typeMismatch) {
    email.setCustomValidity("That does not look like an email address.");
  }
});

email.addEventListener("input", () => email.setCustomValidity(""));

Recuerda limpiar el mensaje personalizado al escribir en el input, o de lo contrario el campo seguirá siendo inválido.

Errores accesibles

La validación solo es útil si los usuarios entienden qué salió mal.

  • Muestra un mensaje de texto claro junto al campo, no solo un borde rojo.
  • Asócialo con el control utilizando aria-describedby.
  • Marca el campo con aria-invalid="true".
  • Mueve el foco al primer campo inválido al enviar el formulario.
  • Resume los errores en la parte superior en formularios largos.
<!-- error.html -->
<label for="email">Email address</label>
<input id="email" name="email" type="email" required
       aria-invalid="true" aria-describedby="email-error" />
<p id="email-error" class="error">Please enter a valid email address.</p>

Nunca dependas únicamente del color; combínalo con texto y un icono.

Valida siempre en el servidor

La validación en el lado del cliente es una funcionalidad de experiencia de usuario, no un control de seguridad. Cualquier persona puede editar la página, desactivar JavaScript o enviar una solicitud directamente. El servidor debe validar los tipos, longitudes, formatos y permisos, y devolver errores claros que el cliente pueda mostrar. Consulta la guía de Web Security.

Mejores prácticas

  • Asigna a cada control una etiqueta visible y asociada.
  • Utiliza el tipo de input correcto y tokens autocomplete.
  • Agrupa los controles relacionados con fieldset y legend.
  • Prioriza las restricciones nativas y luego mejóralas con la Constraint Validation API.
  • Muestra mensajes de error específicos y accesibles cerca del campo.
  • Valida nuevamente en el servidor en cada solicitud.
  • Mantén los formularios cortos y solicita únicamente lo necesario.

Errores comunes

  • Usar placeholders en lugar de labels.
  • Olvidar los atributos name, lo que provoca que los campos no se envíen.
  • Enviar datos sensibles mediante GET.
  • Confiar únicamente en la validación del lado del cliente para la seguridad.
  • Comunicar errores basándose solo en el color.
  • Reiniciar todo el formulario ante un error de validación, provocando la pérdida de los datos ingresados.

Próximos pasos

Los formularios combinan marcado, accesibilidad y validación. Refuerza el marcado con Semantic HTML, hazlo inclusivo con la guía de accesibilidad y gestiona los envíos con JavaScript. Después, audita un formulario de tu aplicación utilizando la lista de verificación anterior.

Etiquetar un input

Una etiqueta visible y asociada es anunciada por los lectores de pantalla y permanece cuando el campo está lleno. Un placeholder desaparece.

Preferir
<label for="email">Email address</label>
<input id="email" name="email"
       type="email" autocomplete="email" />
Evitar
<input name="email" type="email"
       placeholder="Email address" />

Validar input

Usa el tipo nativo y las restricciones, luego valida en el servidor. Las comprobaciones solo de JavaScript pueden ser evadidas por cualquiera que lo desee.

Preferir
<input type="email" name="email"
       required autocomplete="email" />
<input type="password" name="password"
       minlength="8" required />
Evitar
<input name="email" />
<input name="password" />
<!-- checked only after submit -->

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Forms & Validation?

Nuestro tutorial interactivo te guia a traves de Forms & Validation paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.