Validación nativa de formularios en HTML5 sin JavaScript
📚 Contenido de la guía ⌃
- El Mapa Mental: ¿Qué Hace Realmente la Validación Nativa? 🧠
- Con HTML5 + CSS
- Todo a mano con JS
- Tipos de input que Ya Validan por Ti 🧩
- type="email": correos con mínima estructura
- type="url": direcciones con protocolo
- type="tel": el “casi solo UX”
- type="number": números, min/max y la trampa del step
- type="date" y compañía: controles nativos de alto nivel
- Atributos de Restricción: Reglas Declarativas en una Línea 🧱
- pattern: Validación a Medida con Regex 🧬
- Capa Visual: CSS Moderno para Errores y Éxitos 🎨
- Accesibilidad y Seguridad: Lo que HTML5 No Hace por Ti 🛡️
- Accesibilidad (a11y): que el error también se pueda oír
- Seguridad: la validación del cliente no protege tu servidor
- Limitaciones y Estrategia: HTML Primero, JS Después 🚀
- Resumen Rápido: Qué Puede y Qué No Puede la Validación Nativa 📋
¿Alguna vez has rellenado un formulario, le has dado a “Enviar” y… la página se recarga solo para decirte que te faltó un campo? 😤 Durante años, la validación de formularios dependía casi por completo del servidor o de JavaScript.
Hoy tenemos algo mucho más interesante: la validación nativa de formularios en HTML5.
Con solo atributos en el marcado (como required, type="email", pattern…), el navegador puede:
- Detectar errores antes de que los datos salgan del dispositivo.
- Mostrar mensajes y estados visuales de error sin una sola línea de JavaScript.
- Mejorar la experiencia de usuario en móvil (teclados apropiados, selectores de fecha, etc.).
En esta guía vamos a ver la validación nativa como lo que es: una capa declarativa que protege tus formularios y mejora la UX, sin reemplazar jamás la validación del servidor.
El Mapa Mental: ¿Qué Hace Realmente la Validación Nativa? 🧠
Cuando hablamos de “validación nativa”, estamos hablando de tres cosas que el navegador hace por ti:
- Tipado de datos: según el
typedelinput(email, url, number, date…). - Restricciones declarativas: atributos como
required,min,max,minlength,pattern. - Estados visuales: pseudo-clases como
:valid,:invalid,:user-invalidy selectores modernos como:has().
La clave es que todo esto vive en el HTML y el CSS. JavaScript pasa a ser una capa de mejora (para validaciones avanzadas, accesibilidad, lógica de negocio, etc.), no el único guardián.
Con HTML5 + CSS
- Tipos de
inputque ya validan estructura. - Atributos declarativos (
required,pattern…). - Estados visuales con
:user-invalid.
Todo a mano con JS
- Validas cada campo en eventos
submit/input. - Manipulas clases para mostrar errores.
- Si falla el JS, el formulario queda “desnudo”.
Tipos de input que Ya Validan por Ti 🧩
type="email": correos con mínima estructura
Cuando usas <input type="email">, el navegador comprueba que lo que escribe la persona “parece” un email:
que haya algo antes y después de la @, que no haya espacios, etc.
<form>
<label>
Correo electrónico
<input type="email" name="email" required>
</label>
<button type="submit">Enviar</button>
</form>
Importante:
- Es una validación laxa: correos como
fff@fffpueden considerarse válidos sintácticamente. - No comprueba que el correo exista ni que pueda recibir mensajes.
- En móvil, muestra teclado optimizado (con
@y.a la mano).
type="url": direcciones con protocolo
Con <input type="url/>, el navegador espera URLs completas con protocolo:
- Válido:
https://ejemplo.com - Inválido:
www.ejemplo.com(faltahttp://ohttps://)
<label>
Sitio web
<input type="url" name="web" placeholder="https://tusitio.com">
</label>
Esta rigidez es buena para datos limpios, pero a veces tendrás que ayudar al usuario (por ejemplo, prellenando el protocolo).
type="tel": el “casi solo UX”
<input type="tel"/> no valida formato por defecto.
Su misión principal es UX en móvil: mostrar un teclado de marcación más cómodo.
<label>
Teléfono
<input type="tel" name="telefono" placeholder="+57 300 000 0000">
</label>
Si quieres validar el formato del teléfono, deberás usar pattern con una regex pensada para tu zona.
type="number": números, min/max y la trampa del step
<input type="number"/> viene con flechitas y validación numérica. Además, puedes usar:
minymaxpara cotas.steppara definir la “granularidad”.
<label>
Edad
<input type="number" name="edad" min="18" max="99" step="1" required>
</label>
Por defecto step="1", así que si alguien intenta poner 1.5 el campo puede marcarse como inválido (stepMismatch).
Para aceptar decimales:
<input type="number" name="precio" min="0" step="0.01">
Detalles frikis: el navegador trata internamente el valor como número de punto flotante, así que definir bien step y los rangos evita sorpresas raras.
type="date" y compañía: controles nativos de alto nivel
Controles como <input type="date"/>, time, color, etc., ya vienen con:
- Picker o UI integrada (calendario, selector de color…).
- Validación de formato (el valor debe ser una fecha válida).
<label>
Fecha de nacimiento
<input type="date" name="nacimiento" required>
</label>
Ojo: la apariencia de estos controles cambia bastante entre navegadores y sistemas operativos. Si necesitas un diseño ultra custom, a menudo se reimplementan con JS, pero pierdes parte de la validación nativa.
Atributos de Restricción: Reglas Declarativas en una Línea 🧱
Además del tipo, HTML5 te da atributos que funcionan como “puertas lógicas” para decidir si un dato es válido:
required: el campo no puede enviarse vacío.minlength/maxlength: longitud mínima y máxima (texto).min/max: valores mínimo y máximo (números, fechas…).step: tamaño del salto válido en campos numéricos.
<form>
<label>
Nombre de usuario
<input
type="text"
name="username"
required
minlength="5"
maxlength="15"
>
</label>
<label>
Contraseña
<input
type="password"
name="password"
required
minlength="8"
>
</label>
<button type="submit">Crear cuenta</button>
</form>
Detalle interesante: minlength solo aplica si hay texto.
Un campo minlength="5" pero sin required es válido cuando está vacío.
pattern: Validación a Medida con Regex 🧬
pattern es la herramienta para cuando los tipos y atributos básicos se quedan cortos.
Acepta una expresión regular (regex) y el navegador comprueba que el valor coincida al 100% con ese patrón.
Puntos clave:
- La regex está “anclada” implícitamente al inicio y al final (
^...$). - Si el valor no coincide, el campo es
:invalid. - Puedes usar el atributo
titlepara mostrar un mensaje más amigable.
Comentarios y Valoraciones
No hay comentarios aún. ¡Sé el primero en opinar!