La Guía Completa de Formularios HTML y Validación de Restricciones

En este artículo, revisamos los campos de formulario HTML y las opciones de validación ofrecidas por HTML5. También veremos cómo estas pueden mejorarse mediante el uso de CSS y JavaScript.

¿Qué es la Validación de Restricciones?

Cada campo de formulario tiene un propósito. Y este propósito a menudo está regulado por restricciones — o las reglas que rigen lo que debería y no debería ingresarse en cada campo de formulario. Por ejemplo, un campo email requerirá una dirección de correo electrónico válida; un campo password podría requerir ciertos tipos de caracteres y tener un mínimo de caracteres requeridos; y un campo de texto podría tener un límite en la cantidad de caracteres que se pueden ingresar.

Los navegadores modernos tienen la capacidad de verificar que estas restricciones se estén observando por los usuarios, y pueden advertirles cuando esas reglas han sido violadas. Esto se conoce como validación de restricciones.

Validación del lado del cliente vs del lado del servidor

La mayoría del código JavaScript escrito en los primeros años de la lengua se ocupaba de la validación del formulario del lado del cliente. Incluso hoy, los desarrolladores dedican una cantidad significativa de tiempo a escribir funciones para verificar los valores de los campos. ¿Es esto aún necesario en los navegadores modernos? Probablemente no. En la mayoría de los casos, realmente depende de lo que estás tratando de hacer.

Pero primero, un gran mensaje de advertencia:

La validación del lado del cliente es una cortesía que puede prevenir errores comunes de entrada de datos antes de que una aplicación pierda tiempo y ancho de banda enviando datos a un servidor. ¡No es un sustituto de la validación del lado del servidor!

Siempre sanitiza los datos en el servidor. No todas las solicitudes provendrán de un navegador. Incluso cuando lo haga, no hay garantía de que el navegador haya validado los datos. Cualquiera que sepa cómo abrir las herramientas para desarrolladores de un navegador también puede evitar su cuidadosamente elaborado HTML y JavaScript.

Campos de entrada HTML5

HTML ofrece:

Pero usarás <input> con más frecuencia:

<input type="text" name="username" />

El atributo type establece el tipo de control, y hay una amplia variedad de opciones:

type description
button a button with no default behavior
checkbox a check/tick box
color a color picker
date a date picker for the year, month, and day
datetime-local a date and time picker
email an email entry field
file a file picker
hidden a hidden field
image a button which displays the image defined by the src attribute
month a month and year picker
number a number entry field
password a password entry field with obscured text
radio a radio button
range a slider control
reset a button that resets all form inputs to their default values (but avoid using this, as it’s rarely useful)
search a search entry field
submit a form submission button
tel a telephone number entry field
text a text entry field
time a time picker with no time zone
url a URL entry field
week a week number and year picker

El navegador cae de nuevo en text si omite el atributo type o no soporta una opción. Los navegadores modernos tienen un buen soporte para todos los tipos, pero los navegadores antiguos seguirán mostrando un campo de entrada de texto.

Otros atributos útiles de <input> incluyen:

attribute description
accept file upload type
alt alternative text for the image types
autocomplete hint for field auto-completion
autofocus focus field on page load
capture media capture input method
checked checkbox/radio is checked
disabled disable the control (it won’t be validated or have its value submitted)
form associate with a form using this ID
formaction URL for submission on submit and image buttons
inputmode data type hint
list ID of <datalist> autocomplete options
max maximum value
maxlength maximum string length
min minimum value
minlength minimum string length
name name of control, as submitted to server
pattern a regular expression pattern, such as [A-Z]+ for one or more uppercase characters
placeholder placeholder text when the field value is empty
readonly the field is not editable, but it will still be validated and submitted
required the field is required
size the size of the control (often overridden in CSS)
spellcheck set true or false spell-checking
src image URL
step incremental values in numbers and ranges
type field type (see above)
value the initial value

Campos de salida HTML

Además de los tipos de entrada, HTML5 proporciona salidas de solo lectura:

  • output: un resultado de texto de un cálculo o acción del usuario
  • progress: una barra de progreso con atributos value y max
  • meter: una escala que puede cambiar entre verde, ámbar y rojo dependiendo de los valores establecidos para los atributos value, min, max, low, high y optimum.

Etiquetas de Entrada

Los campos deben tener una etiqueta asociada <label>, que puedes envolver alrededor del elemento:

<label>your name <input type="text" name="name" /><label>

O vincular el campo con el atributo id a la etiqueta utilizando un atributo for:

<label for="nameid">your name</label>
<input type="text" id="nameid" name="name" />

Las etiquetas son importantes para la accesibilidad. Puede que hayas encontrado formularios que utilizan un placeholder para ahorrar espacio en la pantalla:

<input type="text" name="name" value="" placeholder="your name" />

El texto del marcador de posición desaparece una vez que el usuario escribe algo, incluso un solo espacio. ¡Es mejor mostrar una etiqueta que obligar al usuario a recordar lo que quería el campo!

Comportamientos de Entrada

Los tipos de campo y los atributos de restricción cambian el comportamiento de entrada del navegador. Por ejemplo, una entrada number muestra un teclado numérico en dispositivos móviles. El campo puede mostrar una rueda y los toques de cursor hacia arriba/hacia abajo en el teclado incrementarán y decrementarán los valores.

La mayoría de los tipos de campo son obvios, pero hay excepciones. Por ejemplo, las tarjetas de crédito son numéricas, pero el spinner de incremento/decremento es inútil y es demasiado fácil presionar hacia arriba o hacia abajo al ingresar un número de 16 dígitos. Es mejor usar un tipo estándar de texto, pero establecer el atributo inputmode en numérico, lo que muestra un teclado adecuado. Establecer autocomplete="cc-number" también sugiere cualquier tarjeta de crédito preconfigurada o previamente ingresada.

El uso del tipo de campo correcto de tipo y autocorrección ofrece beneficios que serían difíciles de lograr en JavaScript. Por ejemplo, algunos navegadores móviles pueden:

Validación automática

El navegador garantiza que el valor de entrada se ajuste a las restricciones definidas por el tipo, min, max, paso, minlength, maxlength, patrón y requerido atributos. Por ejemplo:

<input type="number" min="1" max="100" required />

Intentar enviar un valor vacío impide la presentación del formulario y muestra el siguiente mensaje en Chrome:

Los selectores no permitirán valores fuera del rango de 1 a 100. Se muestran mensajes de validación similares si escribes una cadena que no es un número. Todo sin una sola línea de JavaScript.

Puedes evitar la validación del navegador mediante:

  • agregar un atributo novalidate al elemento <form>
  • agregar un atributo formnovalidate al botón de envío o imagen

Creación de Entradas Personalizadas en JavaScript

Si estás escribiendo un nuevo componente de entrada de fecha basado en JavaScript, ¡por favor detente y alejate de tu teclado!

Escribir controles de entrada personalizados es difícil. Tienes que considerar el mouse, teclado, toque, voz, accesibilidad, dimensiones de la pantalla y qué sucede cuando falla JavaScript. También estás creando una experiencia de usuario diferente. Tal vez tu control es superior al selector de fecha estándar en escritorio, iOS y Android, pero la interfaz de usuario desconocida confundirá a algunos usuarios.

Hay tres razones principales por las que los desarrolladores eligen crear entradas basadas en JavaScript.

1. Los controles estándar son difíciles de estilizar

El estilo CSS está limitado y a menudo requiere hacks, como superponer una entrada con los pseudo-elementos ::before y ::after de su etiqueta. La situación está mejorando, pero cuestiona cualquier diseño que priorice la forma sobre la función.

2. Los tipos modernos de <input> no son compatibles en navegadores antiguos

En esencia, estás codificando para Internet Explorer. Los usuarios de IE no tendrán un selector de fechas pero aún pueden ingresar fechas en formato AAAA-MM-DD. Si tu cliente insiste, entonces carga un polyfill solo en IE. No hay necesidad de cargar a los navegadores modernos.

3. Requieres un nuevo tipo de entrada que nunca ha sido implementado antes

Estas situaciones son poco comunes, pero siempre comienza con campos HTML5 apropiados. Son rápidos y funcionan incluso antes de que el script se cargue. Puedes mejorar progresivamente los campos según sea necesario. Por ejemplo, un toque de JavaScript puede asegurar que la fecha de finalización de un evento del calendario ocurra después de la fecha de inicio.

En resumen: evitar reinventar controles HTML!

Estilo de Validación CSS

Puedes aplicar los siguientes pseudo-clases a los campos de entrada para estilizarlos según el estado actual:

selector description
:focus the field with focus
:focus-within an element contains a field with focus (yes, it’s a parent selector!)
:focus-visible an element has focus owing to keyboard navigation, so a focus ring or more evident styling is necessary
:required a field with a required attribute
:optional a field without a required attribute
:valid a field that has passed validation
:invalid a field that has not passed validation
:user-valid a field that has passed validation after the user has interacted with it (Firefox only)
:user-invalid a field that hasn’t passed validation after the user has interacted with it (Firefox only)
:in-range the value is within range on a number or range input
:out-of-range the value is out of range on a number or range input
:disabled a field with a disabled attribute
:enabled a field without a disabled attribute
:read-only a field with a read-only attribute
:read-write: a field without a read-only attribute
:checked a checked checkbox or radio button
:indeterminate an indeterminate checkbox or radio state, such as when all radio buttons are unchecked
:default the default submit button or image

Puedes estilizar el texto del placeholder de una entrada con el pseudo-elemento ::placeholder:

/* placeholder azul en campos de correo electrónico */
input[type="email"]::placeholder {
  color: blue;
}

Los selectores anteriores tienen la misma especificidad, por lo que el orden puede ser importante. Considera este ejemplo:

input:invalid { color: red; }
input:enabled { color: black; }

Las entradas inválidas tienen texto rojo, pero solo se aplica a las entradas con un atributo disabledpor lo que todas las entradas habilitadas son negras.

El navegador aplica estilos de validación al cargar la página. Por ejemplo, en el siguiente código, cada campo inválido se le da un borde rojo:

:invalid {
  border-color: #900;
}

El usuario se enfrenta a un conjunto intimidante de cajas rojas antes de interactuar con el formulario. Mostrar errores de validación después del primer envío o a medida que se cambia un valor ofrecería una mejor experiencia. Ahí es donde entra JavaScript…

JavaScript y la API de Validación de Restricciones

La API de Validación de Restricciones ofrece opciones de personalización de formularios que pueden mejorar el control de campo HTML estándar. Podrías:

  • evitar la validación hasta que el usuario interactúe con un campo o envíe el formulario
  • mostrar mensajes de error con estilo personalizado
  • proporcionar validación personalizada que es imposible solo con HTML. Esto suele ser necesario cuando necesitas comparar dos entradas, como cuando ingresas una dirección de correo electrónico o un número de teléfono, verifica que los campos de “nuevo” y “confirmar” contraseña tengan el mismo valor, o asegúrate de que una fecha sea posterior a otra.

Validación de Formularios

Antes de usar la API, tu código debería deshabilitar la validación y mensajes de error predeterminados estableciendo la propiedad noValidate del formulario en true (lo mismo que agregar un atributo novalidate):

const myform = document.getElementById('myform');
myform.noValidate = true;

Luego puedes agregar manejadores de eventos, como cuando el formulario se envía:

myform.addEventListener('submit', validateForm);

El manejador puede verificar que todo el formulario es válido usando los métodos checkValidity() o reportValidity(), que devuelven true cuando todos los inputs del formulario son válidos. (La diferencia es que checkValidity() verifica si alguno de los inputs está sujeto a validación de restricciones.)

Las documentación de Mozilla explica:

También se desencadena un evento invalid en cada campo inválido. Esto no se propaga: los controladores deben agregarse a cada control que lo utilice.

// validar formulario al enviar
function validateForm(e) {

  const form = e.target;

  if (form.checkValidity()) {

    // el formulario es válido - realizar verificaciones adicionales

  }
  else {

    // el formulario es inválido - cancelar envío
    e.preventDefault();

  }

};

A valid form could now incur further validation checks. Similarly, an invalid form could have invalid fields highlighted.

Validación de Campos

Los campos individuales tienen las siguientes propiedades de validación de restricciones:

  • willValidate: devuelve true si el elemento es candidato para la validación de restricciones.

  • validationMessage: el mensaje de validación. Esto será una cadena vacía si el campo es válido.

  • valitidad: un objeto ValidityState. Esto tiene una propiedad válido establecida en true cuando el campo es válido. Si es false, uno o más de los siguientes propiedades serán true:

    ValidityState descripción
    .badInput el navegador no puede entender la entrada
    .customError se ha establecido un mensaje de validez personalizado
    .patternMismatch el valor no coincide con el atributo patrón especificado
    .rangeOverflow el valor es mayor que el atributo max
    .rangeUnderflow el valor es menor que el atributo min
    .stepMismatch el valor no cumple con las reglas del atributo paso
    .tooLong la longitud de la cadena es mayor que el atributo maxlength
    .tooShort la longitud de la cadena es menor que el atributo minlength
    .typeMismatch el valor no es un correo electrónico o URL válido
    .valueMissing un valor requerido está vacío

Los campos individuales tienen los siguientes métodos de validación de restricciones:

  • setCustomValidity(message): establece un mensaje de error para un campo inválido. Se debe pasar una cadena vacía cuando el campo sea válido, de lo contrario, el campo permanecerá inválido para siempre.
  • checkValidity(): devuelve true cuando la entrada es válida. La propiedad valitity.valid hace lo mismo, pero checkValidity() también desencadena un evento invalid en el campo, lo cual podría ser útil.

La función de controlador validateForm() podría recorrer cada campo y aplicar una clase invalid a su elemento padre cuando sea necesario:

function validateForm(e) {
  const form = e.target;
  if (form.checkValidity()) {
    // el formulario es válido - realizar más comprobaciones
  }
  else {
    // el formulario es inválido - cancelar el envío
    e.preventDefault();
    // aplicar clase inválida
    Array.from(form.elements).forEach(i => {
      if (i.checkValidity()) {
        // el campo es válido - eliminar clase
        i.parentElement.classList.remove('invalid');
      }
      else {
        // el campo es inválido - agregar clase
        i.parentElement.classList.add('invalid');
      }
    });
  }
};

Suponga que su HTML definió un campo de correo electrónico:

<div>
  <label for="email">email</label>
  <input type="email" id="email" name="email" required />
  <p class="help">Please enter a valid email address</p>
</div>

El script aplica una clase invalid al <div> cuando el correo electrónico no está especificado o es inválido. CSS puede mostrar u ocultar el mensaje de validación cuando el formulario se envía:

.help { display: none; }
.invalid .help { display: block; }
.invalid label, .invalid input, .invalid .help {
  color: red;
  border-color: red;
}

Creando un Validador de Formularios Personalizado

El siguiente ejemplo muestra un formulario de contacto que requiere un nombre de usuario y ya sea una dirección de correo electrónico, un número de teléfono, o ambos:

Se implementa utilizando una clase de validación de formulario genérica llamada FormValidate. Un elemento de formulario se pasa al instanciar un objeto. Un segundo parámetro opcional puede configurarse:

  • true para validar cada campo a medida que el usuario interactúa con él
  • false (el valor predeterminado) para validar todos los campos después del primer envío (la validación de nivel de campo ocurre después de eso)
// validar formulario de contacto
const contactForm = new FormValidate(document.getElementById('contact'), false);

Un método .addCustom(field, func) define funciones de validación personalizadas. El siguiente código asegura que cualquiera de los campos email o tel sean válidos (ninguno tiene atributos required):

// validación personalizada - correo electrónico y/o teléfono
const
  email = document.getElementById('email'),
  tel = document.getElementById('tel');

contactForm.addCustom(email, f => f.value || tel.value);
contactForm.addCustom(tel, f => f.value || email.value);

A FormValidate object monitors both of the following:

  • eventos focusout, que luego verifican un campo individual
  • eventos submit del formulario, que luego verifican cada campo

Ambos llaman al método .validateField(field), que comprueba si un campo pasa la validación de restricciones estándar. Cuando lo hace, cualquier función de validación personalizada asignada a ese campo se ejecuta a su vez. Todos deben devolver true para que el campo sea válido.

Los campos inválidos tienen una clase invalid aplicada al elemento padre del campo, lo que muestra un mensaje de ayuda rojo utilizando CSS.

Finalmente, el objeto llama a una función personalizada submit cuando todo el formulario es válido:

// submit personalizado
contactForm.submit = e => {
  e.preventDefault();
  alert('Form is valid!\n(open the console)');
  const fd = new FormData(e.target);
  for (const [name, value] of fd.entries()) {
    console.log(name + ': ' + value);
  }
}

Alternativamente, puedes usar un addEventListener estándar para manejar eventos submit del formulario, ya que FormValidate evita que se ejecuten más controladores cuando el formulario es inválido.

Form Finesse

Los formularios son la base de todas las aplicaciones web y los desarrolladores dedican mucho tiempo manipulando la entrada del usuario. La validación de restricciones tiene un buen soporte: los navegadores pueden manejar la mayoría de las verificaciones y mostrar opciones de entrada adecuadas.

Recomendaciones:

  • Utiliza los tipos de entrada HTML estándar donde sea posible. Establece los atributos min, max, step, minlength, maxlength, pattern, required, inputmode, y autocomplete según corresponda.
  • Si es necesario, usa un poco de JavaScript para permitir la validación y mensajes personalizados.
  • Para campos más complejos, mejora progresivamente las entradas estándar.

Finalmente: ¡olvídate del Internet Explorer!

A menos que tus clientes sean predominantemente usuarios de IE, no hay necesidad de implementar tus propias funciones de validación de respaldo. Todos los campos de entrada de HTML5 funcionan en IE pero pueden requerir más esfuerzo del usuario. (Por ejemplo, IE no detectará cuando ingreses una dirección de correo electrónico inválida). Todavía tienes que validar los datos en el servidor, así que considera usar eso como base para el control de errores de IE.

Preguntas Frecuentes (FAQs) sobre Formularios HTML y Validación de Restricciones

¿Cuál es la importancia de la validación de formularios HTML?

La validación de formularios HTML es un aspecto crucial del desarrollo web. Garantiza que los datos ingresados por los usuarios en un formulario cumplan con ciertos criterios antes de enviarse al servidor. Esto no solo mantiene la integridad de los datos sino que también mejora la experiencia del usuario al proporcionar retroalimentación inmediata sobre la corrección de los datos ingresados. Sin validación de formularios, existe el riesgo de recibir datos incorrectos, incompletos o incluso maliciosos, lo que puede provocar varios problemas, incluida la corrupción de datos, brechas de seguridad y fallas del sistema.

¿Cómo mejora HTML5 la validación de formularios?

HTML5 introduce varios nuevos elementos y atributos de formulario que facilitan y hacen más eficiente la validación de formularios. Por ejemplo, proporciona nuevos tipos de entrada como email, URL y número, que validan automáticamente los datos de entrada en función del tipo. También introduce nuevos atributos como required, pattern y min/max que te permiten especificar varias restricciones en los datos de entrada. Además, HTML5 proporciona una API de validación integrada que te permite realizar validaciones personalizadas utilizando JavaScript.

¿Puedo realizar la validación de formularios sin JavaScript?

Sí, puedes realizar una validación básica de formularios utilizando solo HTML5. HTML5 proporciona varios nuevos tipos de entrada y atributos que te permiten especificar diversas restricciones en los datos de entrada. Por ejemplo, puedes utilizar el atributo required para hacer un campo obligatorio, el atributo pattern para imponer un formato específico, y los atributos min/max para establecer un rango para la entrada numérica. Sin embargo, para una validación más compleja, es posible que aún necesites utilizar JavaScript.

¿Cómo puedo personalizar los mensajes de error en la validación de formularios HTML5?

HTML5 proporciona una API de validación que te permite personalizar los mensajes de error. Puedes utilizar el método setCustomValidity del objeto ValidityState para establecer un mensaje de error personalizado para un campo. Este método toma un argumento de cadena, que se convierte en el mensaje de validación del campo cuando el campo no es válido. Puedes llamar a este método en respuesta al evento invalid, que se dispara cuando un campo no pasa la validación.

¿Cómo puedo desactivar la validación de formularios HTML5?

Puedes desactivar la validación de formularios HTML5 agregando el atributo novalidate al elemento form. Cuando este atributo está presente, el navegador no realizará ninguna validación en el formulario cuando se envíe. Esto puede ser útil si deseas manejar la validación completamente en el lado del servidor o utilizando JavaScript personalizado.

¿Cómo puedo validar varios campos juntos en HTML5?

HTML5 no proporciona una forma nativa de validar múltiples campos juntos. Sin embargo, puedes lograr esto utilizando JavaScript. Puedes escribir una función de validación personalizada que verifique los valores de varios campos y establezca un mensaje de validez personalizado si no cumplen con los criterios requeridos. Puedes llamar a esta función en respuesta al evento de envío del formulario o a los eventos de entrada/cambio de los campos.

¿Cómo puedo validar un campo basado en el valor de otro campo en HTML5?

HTML5 no proporciona una forma nativa de validar un campo basado en el valor de otro campo. Sin embargo, puedes lograr esto utilizando JavaScript. Puedes escribir una función de validación personalizada que verifique el valor de un campo en relación con el valor de otro campo y establezca un mensaje de validez personalizado si no coinciden. Puedes llamar a esta función en respuesta a los eventos de entrada/cambio de los campos.

¿Cómo puedo realizar una validación asíncrona en HTML5?

HTML5 no admite la validación asíncrona de forma nativa. Sin embargo, puedes lograr esto utilizando JavaScript. Puedes escribir una función de validación personalizada que realice una operación asíncrona, como una solicitud AJAX, y establezca un mensaje de validez personalizado en función del resultado. Puedes llamar a esta función en respuesta a los eventos de entrada/cambio de los campos o al evento de envío del formulario.

¿Cómo puedo dar estilo a los mensajes de error en la validación de formularios HTML5?

La apariencia de los mensajes de error en la validación de formularios HTML5 está determinada por el navegador y no puede ser estilada directamente utilizando CSS. Sin embargo, puedes crear mensajes de error personalizados utilizando JavaScript y estilizarlos como desees. Puedes usar la API de validación para determinar cuándo un campo es inválido y mostrar un mensaje de error personalizado en consecuencia.

¿Cómo puedo probar la validación de un formulario HTML?

Puedes probar la validación de un formulario HTML introduciendo varios tipos de datos en los campos y tratando de enviar el formulario. Debes probar tanto con datos válidos como inválidos para asegurarte de que la validación funciona correctamente en todos los casos. También puedes utilizar herramientas o bibliotecas de prueba automatizada para realizar una prueba más exhaustiva.

Source:
https://www.sitepoint.com/html-forms-constraint-validation-complete-guide/