Working with forms is an every day task for almost every web developer. No matter what site you'll create it will use forms. Validating the form data on the client side is a nice-to-have feature when it comes to user experience. In this tutorial we'll create a simple form validation using javascript.
While client-side form validation gives a nice user experience, it can be tricked and bypassed really easily. To prevent malicious use, you should always validate form data on the server side
Video Tutorial
If you would watch a detailed step-by-step video instead you can check out the video I made covering this project on my Youtube Channel:
HTML
Let's start with the HTML markup. We'll have a container
div, that we'll use to position and style our form. Inside that, not surprisingly, we'll create a form
, we also set an id
for it, and set the action
to /
since we don't really want to submit this form.
We'll create four input fields, for the username, email, password, and password confirmation. For styling and control purposes we'll wrap these input
tags into div
s with the class input control
. Each of these input controls will contain a label
, an input
, and a div
with the class error
. Every input should have an id and name attribute. The label's should have a matching for
property with the corresponding input tag's name attribute. For the input type we will use text
for the username and email, and use password
for the password and the password confirmation. The div with the error
class will hold the error messages for the specific input field. It will be empty for now, we will modify it from javascript.
Lastly, we have to add a button to "submit" our form. In this example we won't really submit the form just simulate it. For the submit button I'll use a button with a type of submit
.
<div class="container">
<form id="form" action="/">
<h1>Registration</h1>
<div class="input-control">
<label for="username">Username</label>
<input id="username" name="username" type="text">
<div class="error"></div>
</div>
<div class="input-control">
<label for="email">Email</label>
<input id="email" name="email" type="text">
<div class="error"></div>
</div>
<div class="input-control">
<label for="password">Password</label>
<input id="password"name="password" type="password">
<div class="error"></div>
</div>
<div class="input-control">
<label for="password2">Password again</label>
<input id="password2"name="password2" type="password">
<div class="error"></div>
</div>
<button type="submit">Sign Up</button>
</form>
</div>
That is the HTML markup that we need for our form. Let's style it a bit with CSS.
CSS
We'll give a simple clean spacious design for this tutorial. I'll set a linear gradient as the background and I'll use a custom google font, that you can install from here.
body {
background: linear-gradient(to right, #0f2027, #203a43, #2c5364);
font-family: 'Poppins', sans-serif;
}
We'll give a fix width to our form, and center it with margins, also I'll give it a top margin to move it down a bit vertically. To have more space we apply 20px of padding. We'll set a fixed font size, a light background color and also set a border radius to have rounded corners.
#form {
width: 300px;
margin: 20vh auto 0 auto;
padding: 20px;
background-color: whitesmoke;
border-radius: 4px;
font-size: 12px;
}
For the form title, we'll use a dark text color, and center it horizontally using text-align: center
. The submit button should stand out so we'll use a blue background color, and white text color. We also remove the browser default borders and give it a little border-radius. We'll give it a little spacing with paddings and margins, and make it full-width by applying 100% width.
#form h1 {
color: #0f2027;
text-align: center;
}
#form button {
padding: 10px;
margin-top: 10px;
width: 100%;
color: white;
background-color: rgb(41, 57, 194);
border: none;
border-radius: 4px;
}
To have the inputs stacked below each other we'll use flexbox. To do that we'll set display: flex;
and flex-direction: column
. For the inputs we'll set a grey border, with a little border-radius. We'll set the display property to block
, and make them full-width, by applying width 100%. We'll also set a little padding, so it'll be more spacious. I'll also remove the outline when the input is in focus, by setting outline: 0
.
.input-control {
display: flex;
flex-direction: column;
}
.input-control input {
border: 2px solid #f0f0f0;
border-radius: 4px;
display: block;
font-size: 12px;
padding: 10px;
width: 100%;
}
.input-control input:focus {
outline: 0;
}
We'll use two classes ("success" and "error") to give visual feedback to the user on whether the input's value is valid or not. We'll apply these classes from javascript to the input-control div which contains the specific input field. When the success class is present we will set a green border color, otherwise if error is present we'll use a red border color instead. For the error div we'll use a smaller font-size and a red color to show the error messages.
.input-control.success input {
border-color: #09c372;
}
.input-control.error input {
border-color: #ff3860;
}
.input-control .error {
color: #ff3860;
font-size: 9px;
height: 13px;
}
Let's do the validation in javascript next!
Javascript
The first thing we have to do is to save references for the form, and the input fields. As we gave id for every input and the form we can easily to do by using getElementById
.
const form = document.getElementById('form');
const username = document.getElementById('username');
const email = document.getElementById('email');
const password = document.getElementById('password');
const password2 = document.getElementById('password2');
To prevent the form for automatically submit we have to attach and event listener to our form's submit
event. In this event handler function we have to call preventDefault()
function to prevent the form from submitting automatically. Instead of submitting we'll call the validateInputs
function, which will validate the inputs and if we want to we can submit the form in there after every check passes, but we won't do that in this tutorial. We'll create this validateInputs
shortly.
form.addEventListener('submit', e => {
e.preventDefault();
validateInputs();
});
We'll also create two helper functions: setError
, setSuccess
. We'll use these helper functions to set the error or success states of the input controls. Let's start with the setError one. It receives two parameters: element
, and message
. The element will be the input element that is in the specific input-control. So first we have to get the input control parent div. We'll save it into the inputControl
variable, and get the input control div by using the parent
property of the input element. Next we have to gather the error div, and save it into a variable. We can do that by querying the input control with the error class.
Now we have to set the error div's innerText to be the message that we got in parameters, and remove the success
class from the input control (if it exists) and add the error class.
const setError = (element, message) => {
const inputControl = element.parentElement;
const errorDisplay = inputControl.querySelector('.error');
errorDisplay.innerText = message;
inputControl.classList.add('error');
inputControl.classList.remove('success')
}
The setSuccess method will be really similar. The first difference is that it won't receive a message as a parameter. We have to clear the error display by setting its innerText to an empty string. Lastly we have to reverse the class application. We'll add the success
class to the inputControl and remove the error
class (if present).
const setSuccess = element => {
const inputControl = element.parentElement;
const errorDisplay = inputControl.querySelector('.error');
errorDisplay.innerText = '';
inputControl.classList.add('success');
inputControl.classList.remove('error');
};
We will create one last helper function to validate emails. This is an optional step, if you don't want to use regular expressions, feel free to just set the input type of the email field to email
. The isValidEmail
function will take a string as a parameter and use this weird looking regular expression to check whether it is a valid email or not. We'll use String.test()
function to test the string against the regex. We'll also convert the email to a string and make it lowercase.
const isValidEmail = email => {
const re = /^(([^<>()[\]\\.,;:\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,}))$/;
return re.test(String(email).toLowerCase());
}
Now we should create the validator validateInputs
function. First we will get the value of all the input fields. We can do that by getting the value property's value of the input field references. We'll call the String.trim()
function to remove the trailing empty spaces (if any) from the start and end of the values.
Then we can start validating inputs. We'll use if, else
statements to do the validation. For the username we will check whether if it is empty or not, by comparing the value with an empty string. If it empty, we'll call the setError
function and provide the username element to it, with our error message. Otherwise we'll call the setSuccess
method with the username element. Now we have to do this for the other input fields, but the approach will be the same.
const validateInputs = () => {
const usernameValue = username.value.trim();
const emailValue = email.value.trim();
const passwordValue = password.value.trim();
const password2Value = password2.value.trim();
if(usernameValue === '') {
setError(username, 'Username is required');
} else {
setSuccess(username);
}
};
For the email we'll check if it is provided or not, and set an error if it is empty. If it is not empty we'll check whether it is a valid email address, and if not we'll set an error, otherwise we set success for the field.
if(emailValue === '') {
setError(email, 'Email is required');
} else if (!isValidEmail(emailValue)) {
setError(email, 'Provide a valid email address');
} else {
setSuccess(email);
}
}
For the password we'll check whether it is empty or not, and if it is not empty we'll check if it is longer than 7 characters. If not, well set an error, otherwise we'll set it as success.
if(passwordValue === '') {
setError(password, 'Password is required');
} else if (passwordValue.length < 8 ) {
setError(password, 'Password must be at least 8 character.')
} else {
setSuccess(password);
}
}
For the password confirmation we'll check if it is empty, and we should also check if the password confirmation's value is equal to the password's value.
if(password2Value === '') {
setError(password2, 'Please confirm your password');
} else if (password2Value !== passwordValue) {
setError(password2, "Passwords doesn't match");
} else {
setSuccess(password2);
}
}
Now we have every input validated, if we wanted to we could submit our form now to a specific endpoint.
Good job now you have a working form validation Javascript. Please note that you always have to validate the form inputs on the server-side as client-side validation can be easily bypassed. There are way more advanced form validation methods and libraries that we use in modern web development, but this project is a really good way to start and learn the fundamentals.
Where you can learn more from me?
I create education content covering web-development on several platforms, feel free to 👀 check them out.
I also create a newsletter where I share the week's or 2 week's educational content that I created. No bull💩 just educational content.
🔗 Links:
- 🍺 Support free education and buy me a beer
- 💬 Join our community on Discord
- 📧 Newsletter Subscribe here
- 🎥 YouTube Javascript Academy
- 🐦 Twitter: @dev_adamnagy
- 📷 Instagram @javascriptacademy
Top comments (19)
Your solution and example is very static and not dynamic.
to make it dynamic i would suggest to use after submitting the form
event.currentTarget.elements
with
event.currentTarget.elements
you will get all the formElements as objectand based on data attribute validation (for example) i would set the validation type. Maybe better is to create a js array of object for your form. On each item you can set the validation type. This is what you can use for validation for the field and form
If you want to have a example let me know
Thanks @rkallan for writing this comment!
Yes, the solution is very static, intentionally. This tutorial’s target audience are the beginners, and I think they get the hang of how it works more easil if the validation is static and not dynamic. Probably would worth to create and advanced form validation tutorial too 🤔
I understand your explanation and I can agree about the static validation as a start
But to get the values of your form elements I would suggest to use
event.currentTarget.elements
The 2 functions setError and setSucces I would created as 1 function
The if statements for validation I would created functions. And avoiding if elseif else statements
And return value would be a object
Hi RRKallan,Thanks for explaining this, can you provide real time working example on the same !!
@anil027
Thank you !!
Not sure we need such as your extravagant example. I think the OP was trying to teach it at its basic level.
I would rather applaud him for being basic and simple.
The OP replayed and explained it why he used the static way. I can agree with the arguments
You're probably better off using the in-built HTML field validation
That can work for simple use cases, but most of the time there are Specific validation conditions. For example the password should contain lowercase, uppercase letters numbers and should not contain special characters (like ?*%). This example can surely be done with built in HTML valodators, but the aim is to get an idea how you can do more advanced validations.
Your password example can be done with built-in validation
Okay lets get into a specific use case I faced a few years earlier. On a registration site we had to validate if an email address is a real existing address. To do that we had to call an API to validate the email address. There’s no way to do that eith built in html.
All the in-built stuff can be called with JS. You just need to augment it a little for cases like this - not re-invent the wheel
When a user use inspect element and change the pattern or and the type the build in validation would result in a false isValid
Similarly, any JS-only validation can be bypassed (breakpoints, changing values etc.)
Far too many sites these days forget this. I've lost count of the number of forms I've 'fooled' into letting me continue as all the validation is done client-side. I've even seen 'server-side' validation fail as the result of a server-side check whose result was being checked on the client-side - something like this:
True submitting a form needs also to be validate on server side.
Thanks, Adam. This is exactly what I was looking for. A simple JavaScript validation that teaches me the basics of how to do this in a static way with JS, not an elaborate program with all the bells and whistles. And thanks for pointing out the backend validation too, I may have let that slip by without thinking all the way through how people can evade the front end pretty easily.
Please don't ever just remove the focus styles from form elements like this:
Some people rely on the visual indicator of focused elements, especially those who use a keyboard to navigate the form.
One thing I noticed in your HTML is that you're not using the native form element types where they exist. For example, the email field should be of type
email
. Not only does this present the user with an appropriate keyboard (device dependent) but you can hook into the default validation provided by the browser, and then remove the regular expression checking from the code.In-fact, by using the HTML form validation attributes (
type=""
,required
,pattern
, etc), you can make your Javascript validation far more generic. That way, you can target all input elements as you need, and the validation will still work across the entire form regardless of whatever form elements are added or removed in the future.For simple checkbox validation
//checkbox validation starts here
if(document.SimpleForm.gender[0].checked==false && document.SimpleForm.gender[1].checked==false)
{
alert('Select your gender');
return false;
}
When HTML
<input type="checkbox" name="gender" value="Male"> Male <br/>
<input type="checkbox" name="gender" value="Female"> Female <br/>
Source: Form validation in javascript