How to create your instant form validation

Yuki C.
5 min readDec 14, 2018

--

Photo by Brendan Church on Unsplash

It is easy to use any libraries in JavaScript to add validations, however, have you ever wonder how the form validation works? Let’s see how we can roll out our own form validations with error messages!

What we are going to create today

First step: create your patterns!

In the last few days, I tried to create my own form validation system for learning purpose. First we can do is: to create the basic structure of form.

The most important thing in this snippet is the pattern property in all input elements. The mysterious string in the pattern is Regular Expressions (RegEx), that means if the user input anything that mismatch the pattern, it becomes invalid.

For example, there is a store that only sold apple, and they have a form that allows user to input what fruit they want.

Unfortunately, they only have apple, so they can restrict people to enter apple only by using pattern="apple". Thus, all users can only enter apple, otherwise, the form becomes invalid.

Of course, no shop would do this, just for example :)

Step 2: hide the error message

Now, you form is ready, but the error message is always under the input element. How can we fix it?

We can use CSS to control the visibility of this element.

.c-form-label {
display: block;
margin: 1em 0 0.2em 0;
font-size: 0.8em;
text-transform: uppercase;
color: rgba(25, 25, 25, 0.8);
}
.c-form-label abbr {
text-decoration: none;
}
.u-alert {
display: block;
height: 0;
opacity: 0;
height: 0;
overflow: hidden;
transition: ease 400ms;
font-size: 0.8em;
}
.u-alert.invalid {
color: red;
opacity: 1;
height: auto;
max-height: none;
margin-top: 0.3em;
}

The base class of error message is u-alert, its default is opacity: 0 and height: 0. Of course, need to add overflow: hidden, otherwise it would still occupy your spaces.

If the form is invalid, we will add invalid class to this error message (later via JavaScript). You can see, if it adds invalid class, its opacity becomes 1 and height: auto.

You may wonder why we won’t use display: none at u-alert class, the reason is that we want to have transitions between valid and invalid state. That’s why I added transition: ease 400ms at the end.

Step 3: trigger the error message

After hiding our error messages, now it’s time to trigger the error message!

First, we need to get all inputs in the page, using Array.prototype.slice.call(document.getElementsByTagName(‘input’)). Then, the browser will automatically get all inputs.

Tips: Why I would use slice here is for supporting IE11, as IE11 treats document.getElementsByTagName(‘input’) as NodeList, not an array. We cannot directly use forEach without transforming to array. (Well, I know IE11 don’t support arrow function. but this is just for demonstration purpose.)

The magic is coming!

input.forEach(item => {
if (item.type !== 'submit' && item.type !== 'checkbox') {
//add event listener for input
item.addEventListener('input', function(e){
isValid(e);
})
}

Using event listener “input” (which supports well in all browsers), you can detect the validity when user is typing.

The difference between “change” and “input” is, change will trigger only after user stop typing and did not select that input element right now (out of focus). Input is continuously responses when user is typing or selecting something.

Step 4: instant validation is coming! Yay!

The last thing we need here is the “isValid” function. It uses the validation in browser (via the pattern property), you can get the valid status using document.getElementById(<your-element>).validity.valid and it returns boolean true or false.

Then add this CSS to make it works better:

.c-form-input {
display: block;
border-color: rgba(25, 25, 25, 0.1);
border-width: 0 0 2px 0;
padding: 0.2em 2em 0.2em 0;
transition: border-color ease 300ms;
background-repeat: no-repeat;
background-size: 20px 20px;
background-position: 99% 50%;
width: 100%;
}
.c-form-input:focus {
border-color: #03A9F4;
}
.c-form-input[aria-invalid="false"] {
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%234CAF50' d='M9.984 17.016l9-9-1.406-1.453-7.594 7.594-3.563-3.563-1.406 1.406zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>");
margin-bottom: 0;
}
.c-form-input[aria-invalid="true"] {
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%23F44336' d='M17.016 15.609l-3.609-3.609 3.609-3.609-1.406-1.406-3.609 3.609-3.609-3.609-1.406 1.406 3.609 3.609-3.609 3.609 1.406 1.406 3.609-3.609 3.609 3.609zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>");
border-color: red;
margin-bottom: 0;
}

Tips: You can also use .c-form-input:invalid and .c-form-input:valid to create valid / invalid effects, but it will always show even the form is empty. That means when user first visit your form, they will see lots of red crosses!

Using aria-invalid to style input elements is good for both accessibility and user experience, since user will not see lots of red crosses when they visit your form at the first time.

For the background image, I have used inline SVG because:

  1. I don’t want to link the SVG from my GitHub page
  2. It should be faster for loading performance, if browser did not need to get SVG from GitHub

(Icons are from Material Icon and get inline SVG from Icomoon)

Tips: for submission, you need to create a new function & event listener and add preventDefault() inside, otherwise it will show default error popup! (which is not very good-looking)

At the end

You can view my finished form here with styles and extra gimmicks like debounce function and custom event for auto complete validation.

Hope you learn more about form validation! What is your thoughts on form validation? Do you have better ways to do so? Feel free to let me know! :)

--

--

Yuki C.

I am a self-taught front end developer based in Hong Kong! Mostly focused in front-end tech, e.g. React and SASS. Welcome to connect with me!