How to Validate Javascript Forms for Beginners
How to Validate Javascript Forms for Beginners

In this post we will implement together the basic validation of forms inside plain Javascript.

Prepared files

I already prepared a web page where we have a registration form. As you can see here we have just HTML and CSS form with no Javascript.

Register form

And actually I created this project in a separate post.

Here is our HTML with the markup for the whole form.

<!DOCTYPE html>
<html>
  <head>
    <title>This is the title of the webpage</title>
    <link rel="stylesheet" href="main.css" />
  </head>
  <body>
    <div class="form-container">
      <div class="form-container__details">
        <div class="form-container__title">Registration</div>
        <div class="form-container__subtitle">
          Welcome to Monsterlessons Academy
        </div>
      </div>
      <form class="form js-form">
        <div class="form__field">
          <div class="form__label">Name</div>
          <input class="form__input js-name-input" />
          <div class="form__error js-error"></div>
        </div>
        <div class="form__field">
          <div class="form__label">Email</div>
          <input class="form__input js-email-input" />
          <div class="form__error js-error"></div>
        </div>
        <div class="form__field">
          <div class="form__label">Password</div>
          <input class="form__input js-password-input" type="password" />
          <div class="form__error js-error"></div>
        </div>
        <button class="form__submit">Register</button>
      </form>
      <div class="form-container__line-divider"></div>
      <div class="form-container__links">
        <a href="#" class="form-container__link">Login</a>
        <a href="#" class="form-container__link">Forgot password</a>
      </div>
    </div>
    <script src="main.js"></script>
  </body>
</html>

You might wondering what is this strange notation with two underscores. This is because we used BEM methodology (block, element, modifier) to write this CSS. It is not relevant for our validation form but it helps us to structure HTML and CSS.

Most interesting for us here is class form__error which is an empty div where inside we will render our error messages.

And here is how our CSS looks like

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: inherit;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #037ef3;
  padding: 50px 0;
}

.form-container {
  width: 100%;
  background: #fff;
  padding: 30px;
  max-width: 450px;
  border-radius: 10px;
  box-shadow: rgba(3, 3, 3, 0.1) 10px 0px 50px;
}

.form-container__details {
  margin-bottom: 40px;
  text-align: center;
}

.form-container__title {
  font-size: 38px;
  color: #555;
  margin-bottom: 7px;
}

.form-container__subtitle {
  font-size: 18px;
  color: #999;
}

.form__field {
  margin-bottom: 10px;
}

.form__label {
  margin-bottom: 10px;
  font-size: 15px;
  font-weight: 600;
  color: #777;
}

.form__input {
  width: 100%;
  padding: 25px 15px;
  border: 0;
  background: #f0f0f0;
  border-radius: 5px;
  font-size: 18px;
  color: #555;
  font-weight: 600;
  border: 1px solid #b3adac;
}

.form__submit {
  background: #037ef3;
  color: #fff;
  font-weight: 600;
  width: 100%;
  border-radius: 5px;
  cursor: pointer;
  padding: 25px 15px;
  border: 0;
  transition: all 0.8s;
  font-size: 18px;
}

.form__submit:hover {
  background: #0271da;
}

.form-container__line-divider {
  background: #037ef3;
  width: 30px;
  height: 3px;
  border-radius: 50px;
  margin: 30px auto;
}

.form-container__links {
  display: flex;
  justify-content: space-between;
}

.form-container__link {
  font-size: 15px;
  font-weight: 600;
  color: #777;
}

.form__field--error input {
  border: 1px solid #e74c3c;
}

.form__error {
  color: #e74c3c;
  margin-top: 10px;
  height: 20px;
}

@media (max-width: 600px) {
  .form-container {
    padding: 30px 25px;
    width: 90%;
  }
  .form__input,
  .form__submit {
    padding: 18px 15px;
  }
}

If you want to try it yourself and not just follow along you can take a source code in the description box below.

Validating form

Here I have an empty main.js and first of all we want to create references to our DOM elements. The main point is that I don't want to use classes that we already have for references. I want to add to form and all input classes with js prefix. In this cases every developer will understand that it is used for Javascript and they should not be deleted.

const form = document.querySelector(".js-form");
const $nameInput = document.querySelector(".js-name-input");
const $emailInput = document.querySelector(".js-email-input");
const $passwordInput = document.querySelector(".js-password-input");

Also I used $ sign before each name to show that it is a DOM element and not just a variable.

Attaching event listeners

Now we want to listen to submitting of our form to show validation.

form.addEventListener("submit", (e) => {
  e.preventDefault();
  validate();
});

Here inside our submit listener we prevented the default form behaviour and called validate method which we will create in a second.

const validate = () => {
  const nameValue = $nameInput.value.trim();
  const emailValue = $emailInput.value.trim();
  const passwordValue = $passwordInput.value.trim();
};

Here we added a validate form where we read all values from our inputs. To make sure that there are no spaces at the beginning or at the end we use trim function.

Now I want to create additional function highlightError which will show an error message and highlight the specific field.

const highlightError = ($input, errorMessage) => {
  $input.parentNode.classList.add("form__field--error");
  $input.nextElementSibling.innerText = errorMessage;
};

Here we get DOM node and an error message as parameters. We set an error message on the error element we used nextElementSibling method to find it.

const validate = () => {
  ...
  if (!nameValue) {
    highlightError($nameInput, "Name can't be blank");
  }
}

Now we can highlight specific field if the value is not there.

Let's do it for all fields.

const validate = () => {
  ...
  if (!nameValue) {
    highlightError($nameInput, "Name can't be blank");
  }
  if (!emailValue) {
    highlightError($emailInput, "Email can't be blank");
  }

  if (!passwordValue) {
    highlightError($passwordInput, "Password can't be blank");
  }
}

But here is a problem. After we once get an error even if we change the value and input is valid is stays invalid. For this we can create clearError function.

const clearError = ($input) => {
  $input.parentNode.classList.remove("form__field--error");
  $input.nextElementSibling.innerText = "";
};

It simply removes validation from the DOM node.

Now we need to call this function for each DOM not in the validate method.

const validate = () => {
  const nameValue = $nameInput.value.trim();
  const emailValue = $emailInput.value.trim();
  const passwordValue = $passwordInput.value.trim();

  clearError($nameInput);
  clearError($emailInput);
  clearError($passwordInput);

  ...
};

And the last improvement that we can do is validate a password not only for emptiness but also for validity. Let's create an additional function for this.

const isEmail = (email) => {
  return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
    email
  );
};

Here we used a regular expression to validate a string. You should not understand it and you can just find it in internet when you need to validate an email.

Now let's adjust our email validation.

  if (!emailValue) {
    highlightError($emailInput, "Email can't be blank");
  } else if (!isEmail(emailValue)) {
    highlightError($emailInput, "Email is not valid");
  }

Here is how it looks like now.

Validation errors

And if you want to fully understand how we wrote CSS and HTML for this project make sure to check this post also.

📚 Source code of what we've done