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.
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.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done