Cómo crear y validar hermosos formularios con HTML, CSS y JS de Vanilla

Las formas son difíciles.  

Saber cómo recopilar y validar correctamente los datos del usuario es una de las habilidades más importantes que debe tener un desarrollador de frontend. Pero es difícil porque abundan los casos extremos.

Debe considerar todas las formas en que un usuario podría romper su pequeño formulario y, al mismo tiempo, brindar una excelente experiencia de usuario.

La pieza de UX es importante porque las formas son los guardianes de las conversiones de productos y servicios. Si usted, como desarrollador front-end, se equivoca, podría haber consecuencias financieras importantes.

Esta es la razón por la que existen miles (una ligera exageración) de bibliotecas de formularios que implementan las mejores prácticas de la industria.  

No hay nada de malo en utilizar estas bibliotecas. El problema surge cuando los desarrolladores los usan sin comprender cómo funcionan realmente los formularios y por qué ciertos patrones se consideran estándares .

Les mostraré cómo crearía un formulario de registro desde cero, usando solo HTML, CSS y JavaScript.

Ok, sin más preámbulos, profundicemos.

La trampa de estado único (predeterminado)

Escritorio

Móvil

Cuando se le presenta un diseño como este, su primera pregunta debería ser, ¿cuántos estados no están representados aquí?

Los ejemplos anteriores representan un estado (cuando un usuario visita la página de inicio de sesión, esto es lo que verá en el escritorio y en el móvil).

Otros estados incluirían:

  • Estado de error
    • ¿Qué sucede si ingreso un correo electrónico que ya existe?
  • Estado de carga
    • ¿Qué sucede cuando envío el formulario?

Al planificar su trabajo, asegúrese de considerar lo que no está en el diseño y debe tenerse en cuenta. Debe revisar cuidadosamente los requisitos de las funciones y hacer preguntas si cree que falta algo.

Requisitos de funciones

Hablando de requisitos ...

Como desarrollador, a menudo se le presentará un PRD (documento de requisitos del producto) de un gerente de producto, diseñador o gerente de proyecto.

Estos documentos generalmente se dividen en historias de usuarios individuales que ejecutará durante un sprint.

Poniéndome el sombrero de gerente de producto, estos son los requisitos de funciones para nuestro formulario:

  • El usuario debe proporcionar una dirección de correo electrónico.
  • La contraseña debe tener al menos 10 caracteres y contener al menos una letra mayúscula, un número y un carácter especial.
  • Debemos mostrar mensajes de error al usuario cuando no cumpla con los requisitos.

Margen

El primer código que escribiremos será HTML con solo una pizca de CSS.  

No parece mucho todavía, pero hay un buen trabajo aquí. Vamos a sumergirnos un poco.

  • Hemos configurado elementos laterales y principales junto con nuestro formulario.
  • Estoy usando BEM como guía para crear nombres de clases y elementos HTML semánticos para facilitar la lectura.
  • Nuestra página de registro adopta un enfoque móvil primero, lo que significa que primero escribimos estilos móviles y agregamos puntos de interrupción para los estilos de escritorio.
  • Estoy aprovechando la cuadrícula CSS para el diseño general y Flexbox para los elementos de posición en la sección principal.
  • Agregué un detector de eventos de envío para el formulario junto con una función de controlador de eventos que simplemente registra el objeto de evento por ahora.

Validación

Aprovechemos algo de lógica de validación incorporada eligiendo nuestros tipos de entrada sabiamente. Usaremos lo siguiente:

  • Tipo de entrada de correo electrónico
  • Tipo de entrada de contraseña

El tipo de entrada de correo electrónico nos da un par de buenas validaciones de forma gratuita.

  1. Comprueba para asegurarse de que @se utiliza el símbolo
  2. También comprueba que haya texto después del símbolo.

Dado que tanto el correo electrónico como la contraseña son obligatorios, agreguemos el requiredatributo a ambos elementos. También agregaremos un minlengthatributo a la entrada de la contraseña.

 Sign up with Github   Twitter Or sign in with email and password Sign Up 

El type=emailatributo le dice al navegador que debe validar la entrada como un correo electrónico.

El minlengthatributo en la entrada de la contraseña nos da este útil mensaje de error:

Ahora, en nuestra función handleSignupFormSubmit, podemos usar la API FormData para obtener los valores de nuestro formulario y, finalmente, enviarlos a una API.

function handleSignupFormSubmit(e) { // prevent default browser behaviour e.preventDefault(); const formDataEntries = new FormData(signupForm).entries(); const { email, password } = Object.fromEntries(formDataEntries); // submit email and password to an API }

Error de mensajes

The error messages that are rendered by the browser are helpful to start, but what if you want these messages to render below their respective form input?  What if you want to control how they look?

Sadly, the browser doesn't give us any control over how the default error message are rendered. So this is where our dkh-form-field__messages div elements come into play. We can render our custom error messages inside these elements.

Let's write a couple custom validation functions to check that our user's password and email values meet the requirements.

 function validatePassword(password, minlength) { if (!password) return 'Password is required'; if (password.length < minlength) { return `Please enter a password that's at least ${minlength} characters long`; } const hasCapitalLetter = /[A-Z]/g; if (!hasCapitalLetter.test(password)) { return 'Please use at least one capital letter.'; } const hasNumber = /\d/g; if (!hasNumber.test(password)) { return 'Please use at least one number.'; } return ''; }
function validateEmail(email) { if (!email) return 'Email is required'; const isValidEmail = /^\[email protected]\S+$/g if (!isValidEmail.test(email)) { return 'Please enter a valid email'; } return ''; }

The regex /^\\[email protected]\\S+$/g is far from bullet proof, but it at least checks to make sure there are characters before and after the @ symbol.  

The best way to validate an email is to send a confirmation email to any user that signs up. The user would then have to open that email and click a link to confirm that their email address is valid.

If you'd like to dig deeper into client side email validation, this is a great thread.

Now, let's figure out how to render the error messages to the page.

function handleSignupFormSubmit(e) { // prevent default browser behaviour e.preventDefault(); const formDataEntries = new FormData(signupForm).entries(); const { email, password } = Object.fromEntries(formDataEntries); const emailErrorMessage = validateEmail(email); const passowrdErrorMessage = validatePassword(password); if (!emailErrorMessage) { // select the email form field message element const emailErrorMessageElement = document.querySelector('.email .dkh-form-field__messages'); // show email error message to user emailErrorMessageElement.innerText = emailErrorMessage; } if (passowrdErrorMessage) { // select the email form field message element const passwordErrorMessageElement = document.querySelector('.password .dkh-form-field__messages'); // show password error message to user passwordErrorMessageElement.innerText = passowrdErrorMessage; } }

One additional thing I'll call out: in order for these messages to show up, we need to remove the required attributes from both the email and password inputs.

We need to change the type attribute value for the email input.

We also need to remove the minlength attribute from the password input.

Updating these attributes removes the browser-based validation in favor of our own validation logic. Here's how our custom error messages will render:

Styles

I leave CSS until the end because, in my personal experience, it's a little harder to focus on logic when the visual design is complete.  

When a component or page "looks" done to the eye it can create a false sense that it is actually done. I don't have any research to back this up, just my personal opinion.

Here's the state of our code after adding quite a bit of CSS.

Desktop

Mobile

Error State

I included font awesome icons for the Github and Twitter Buttons.

 Sign up with  Github    Twitter 

Summary

We have created the building blocks to build sign up and log in forms without 3rd party libraries. You can check out the final source code here.

If you're using a framework like React or Vue, there are a ton of awesome form and validation libraries. You can lean on them to get the job done quickly.

However, if you're new to software development, I would encourage you to focus on the fundamentals first before using these tools.

I got my first job as a developer five years ago and my journey into tech has forever changed my life for the better. I believe that it's important to focus on and master the fundamentals so that you can more easily grasp tools like React and Vue.

One of the problems I noticed when running a meetup myself for years was that people who were new to coding reached for libraries and frameworks too quickly. This ended up hurting them and many struggled during interviews.

If you are learning how to code and could use some help, feel free to reach out to me on twitter. Looking forward to helping however I can.