API de Validación de Restricciones de JavaScript
Aprende la API de Validación de Restricciones de HTML5 en JavaScript: checkValidity, reportValidity, setCustomValidity, el objeto ValidityState, mensajes de error personalizados, coincidencia de patrones y validación de formularios en tiempo real.
JavaScript es un lenguaje esencial para el desarrollo web que permite contenido dinámico e interacción mejorada con el usuario. Un aspecto crítico de JavaScript en los formularios web es la API de Validación de Restricciones de HTML5. Esta guía explora la API en profundidad — sus métodos, el objeto ValidityState y cómo crear mensajes personalizados y retroalimentación en tiempo real — con ejemplos prácticos para desarrolladores principiantes y experimentados.
Esta página se basa en el trabajo con formularios en el DOM y en el evento y método submit. Si necesitas leer o enviar los datos del formulario tras su validación, consulta propiedades y métodos de formulario y FormData.
Introducción a la API de Validación de Restricciones de HTML5
La API de Validación de Restricciones de HTML5 proporciona validación nativa del lado del cliente para elementos de formulario, detectando errores antes de que se envíe el formulario. Las restricciones se declaran directamente en el HTML mediante atributos como required, type="email", min, max, minlength, maxlength, step y pattern. El navegador las aplica automáticamente y las expone a JavaScript para que puedas personalizar la experiencia.
La validación del lado del cliente hace que los formularios se sientan más ágiles y reduce los viajes innecesarios al servidor. Sin embargo, no es una barrera de seguridad — un usuario puede saltársela por completo desactivando JavaScript o creando su propia solicitud. Siempre valida de nuevo en el servidor.
La superficie de la API de Validación de Restricciones
Todo elemento asociado a un formulario (<input>, <textarea>, <select>, <button>, <fieldset> y el propio <form>) expone el mismo pequeño conjunto de miembros.
Métodos
element.checkValidity()— devuelvetruesi el elemento satisface todas sus restricciones, de lo contrariofalse. En caso de fallo, también dispara un eventoinvalidsobre el elemento.element.reportValidity()— similar acheckValidity(), pero además muestra la burbuja de error nativa del navegador para el primer campo inválido. Útil cuando deseas la interfaz nativa sin un mensaje personalizado.element.setCustomValidity(message)— establece un string de error personalizado. Una cadena no vacía marca el elemento como inválido; una cadena vacía ('') limpia el error personalizado y permite que el elemento vuelva a ser válido.form.checkValidity()/form.reportValidity()— valida todos los controles del formulario a la vez.
Propiedades
element.validity— un objetoValidityStatede solo lectura que describe por qué el campo es inválido.element.validationMessage— el mensaje localizado que el navegador mostraría para el estado inválido actual (vacío cuando es válido).element.willValidate—truesi el elemento será comprobado durante la validación (los campos deshabilitados yreadonlyse omiten).
El objeto ValidityState
element.validity expone un boolean para cada tipo de fallo, más valid:
| Propiedad | true cuando… |
|---|---|
valueMissing | un campo required está vacío |
typeMismatch | el valor es del tipo incorrecto (p. ej., un type="email" malformado) |
patternMismatch | el valor no coincide con el atributo pattern |
tooShort / tooLong | el valor es más corto/largo que minlength/maxlength |
rangeUnderflow / rangeOverflow | un número/fecha está por debajo de min o por encima de max |
stepMismatch | el valor no encaja en el incremento step |
customError | se proporcionó a setCustomValidity() un mensaje no vacío |
valid | el campo cumple todas las restricciones |
Inspeccionar estos indicadores te permite adaptar el mensaje al problema exacto:
const input = document.querySelector('#age');
const v = input.validity;
if (v.valueMissing) {
input.setCustomValidity('Age is required.');
} else if (v.rangeUnderflow) {
input.setCustomValidity('You must be at least 18.');
} else {
input.setCustomValidity(''); // clears the custom error
}Configurando tu primera validación
Antes de adentrarte en reglas complejas, comienza con lo básico: verificar que un campo required no esté vacío.
Añadir el atributo novalidate a un formulario deshabilita la interfaz de validación predeterminada del navegador. La API de Validación de Restricciones sigue funcionando en JavaScript — checkValidity() y validity permanecen precisos — por lo que puedes crear tu propia retroalimentación suprimiendo las burbujas nativas.
<form id="registrationForm" novalidate>
<label for="username">Username:</label>
<input type="text" id="username" required />
<button type="submit">Register</button>
<span id="usernameError" style="color: red;"></span>
<span id="registerSuccess" style="color: green; display: none;">Registration successful!</span>
</form>
<script>
document.getElementById('registrationForm').addEventListener('submit', function(event) {
event.preventDefault();
const input = document.getElementById('username');
const usernameError = document.getElementById('usernameError');
const registerSuccess = document.getElementById('registerSuccess');
if (!input.checkValidity()) {
usernameError.textContent = 'Username is required.';
registerSuccess.style.display = 'none'; // Hide success message if visible
} else {
usernameError.textContent = ''; // Clear error message
registerSuccess.textContent = 'Registration successful!';
registerSuccess.style.display = 'block'; // Show success message
input.value = ''; // Reset the username input
}
});
</script>Este fragmento de código demuestra la configuración básica en la que se utiliza input.checkValidity() para hacer que un campo sea obligatorio. El formulario mostrará un mensaje de error si el campo de nombre de usuario se deja vacío.
Implementando mensajes de validación personalizados
Más allá de los mensajes de alerta predeterminados del navegador, puedes crear una experiencia de usuario más integrada mostrando mensajes de error personalizados dentro del diseño HTML. A continuación se explica cómo implementarlo:
Ten en cuenta que la validación de correo electrónico predeterminada de HTML5 puede no requerir un dominio de nivel superior, lo que permite que entradas como w3docs@aol pasen como válidas. Para garantizar que las direcciones de correo incluyan un dominio, hemos añadido el patrón más estricto .+@.+\..+ al campo de correo electrónico. Esta expresión regular requiere al menos un punto después del símbolo @, aproximándose más a los formatos de correo electrónico del mundo real. (Para aprender la sintaxis de expresiones regulares detrás de los patrones, consulta anclajes para el inicio y el final de cadenas.)
<form id="contactForm" novalidate>
<label for="email">Email:</label>
<input type="email" id="email" pattern=".+@.+\..+" required />
<button type="submit">Submit</button>
<span id="emailError" style="color: red"></span>
<span id="successMessage" style="color: green; display: none;">Submission successful!</span>
</form>
<script>
document.getElementById("contactForm").addEventListener("submit", function (event) {
event.preventDefault(); // Prevent default form submission
const email = document.getElementById("email");
const errorMessage = document.getElementById("emailError");
const successMessage = document.getElementById("successMessage");
if (!email.checkValidity()) {
errorMessage.textContent = "Please enter a valid email address, including a domain."; // Display custom error message
successMessage.style.display = "none"; // Hide success message if visible
} else {
errorMessage.textContent = ""; // Clear the error message
successMessage.textContent = "Submission successful!";
successMessage.style.display = "block"; // Show success message
email.value = ""; // Reset the email input
}
});
</script>Este código mejora la experiencia del usuario al proporcionar retroalimentación inmediata e integrada sobre la validez de la entrada de correo electrónico.
Mejorando las validaciones de formulario con patrones
A veces son necesarias validaciones más específicas, como verificar que la entrada se ajusta a un patrón determinado. Esto se usa habitualmente para números de teléfono, códigos postales y campos similares. El atributo pattern está implícitamente anclado — el valor completo debe coincidir — por lo que [0-9]{3}-[0-9]{3}-[0-9]{4} acepta 123-456-7890 pero rechaza 1234567890.
<form id="signupForm" novalidate>
<label for="phone">Phone (XXX-XXX-XXXX):</label>
<input type="tel" id="phone" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" required />
<button type="submit">Sign Up</button>
<span id="phoneError" style="color:red;"></span>
<span id="successMessage" style="color:green; display:none;">Submission successful!</span>
</form>
<script>
document.getElementById('signupForm').addEventListener('submit', function(event) {
const phone = document.getElementById('phone');
const phoneError = document.getElementById('phoneError');
const successMessage = document.getElementById('successMessage');
if (!phone.checkValidity()) {
phoneError.textContent = 'Please enter a phone number in the format XXX-XXX-XXXX.';
successMessage.style.display = 'none'; // Hide success message if present
} else {
phoneError.textContent = '';
phone.value = ''; // Reset the input field
successMessage.textContent = 'Submission successful!';
successMessage.style.display = 'block'; // Show success message
}
});
</script>Este ejemplo utiliza el atributo pattern para especificar que el número de teléfono debe coincidir con un formato específico, mejorando la calidad de los datos recopilados a través del formulario.
Validación en tiempo real con el objeto ValidityState
Esperar hasta el envío puede resultar lento. Escuchando el evento input y leyendo los indicadores de validity, puedes proporcionar retroalimentación mientras el usuario escribe y elaborar un mensaje para el fallo exacto:
<form id="profileForm" novalidate>
<label for="user">Username (3-12 letters/digits):</label>
<input type="text" id="user" pattern="[A-Za-z0-9]{3,12}" required />
<span id="userMsg" style="color:red;"></span>
</form>
<script>
const user = document.getElementById('user');
const msg = document.getElementById('userMsg');
user.addEventListener('input', function () {
const v = user.validity;
if (v.valueMissing) {
msg.textContent = 'Username is required.';
} else if (v.patternMismatch) {
msg.textContent = 'Use 3-12 letters or digits only.';
} else {
msg.textContent = ''; // valid
}
});
</script>Aquí valueMissing y patternMismatch provienen directamente del objeto ValidityState, por lo que un único manejador informa la razón precisa sin necesidad de reimplementar manualmente las reglas.
Combinando reglas declarativas y personalizadas
Algunas comprobaciones — como "las contraseñas deben coincidir" — no pueden expresarse con atributos HTML. Usa setCustomValidity() para incorporarlas al mismo flujo de validación:
const password = document.getElementById('password');
const confirm = document.getElementById('confirm');
confirm.addEventListener('input', function () {
if (confirm.value !== password.value) {
confirm.setCustomValidity('Passwords do not match.');
} else {
confirm.setCustomValidity(''); // clear so the field becomes valid
}
});Dado que el error personalizado participa en checkValidity(), el manejador de envío del formulario no necesita ningún caso especial — el campo con valores distintos simplemente se reporta como inválido como cualquier otro.
Conclusión
La API de Validación de Restricciones de HTML5 es una herramienta poderosa para los desarrolladores web que desean implementar validación de formularios del lado del cliente. No solo mejora la experiencia del usuario al proporcionar retroalimentación inmediata, sino que también reduce la carga en el servidor. Siguiendo los ejemplos de esta guía, puedes crear formularios web más robustos, eficientes y fáciles de usar. Para obtener retroalimentación en tiempo real, considera también escuchar los eventos input o change junto con el manejador de envío.