Back to the Browser: React Form Validation with the DOM API

Sergio Marin
ITNEXT
Published in
4 min readFeb 18, 2019

--

Last week I wrote an article about how we can build a form validation hook with React Hooks (more about it here)

But just after finishing the article I started to think “Ok, but we know that almost all the validation in this example could be done just using the DOM API”, and that is the story of how this article was born.

Because of all the fancy and awesome technology that we have right now we have forgotten to check out what is implemented in the newest versions for the browser (I'm talking about myself).

We have features like web components and we don’t take advantage of that because of our beloved frameworks/libraries (Vue.js, React, Angular, Polymer, etc). I have some slides about web components here, but this post is not about that, is about what the browser can do for us today about form validation.

The browser right now supports form validation and maybe you have used it before. Something like

<input type='text'
name='firstName'
id='firstName'
minlength='2'
pattern='[a-zA-Z]*'
required
/>

This is a pretty simple validation, where is validating the minimum length of the string, the existence of a value of the input, and validates against a regular expression pattern searching for characters from “a” to “z” in lower case or upper case.

This is great, but how can we integrate this with… I don’t know… React? Well, let's do it!

First, let's remove the browser's interface for those errors

because they are kinda ugly.

<form id="my-super-form" novalidate>
<input type='text'
name='firstName'
id='firstName'
minlength='2'
pattern='[a-zA-Z]*'
required
/>
</form>

Is important to mention that putting the “novalidate” attribute to form tag doesn’t mean that you can use browser validation, only means that you need to write and a small little piece of code for it.

checkValidity Method and reportValidity

If we take that form and we run the method checkValidity we are running, in fact, the validation of the browser. This method is available for all form-related tags: form, input, select, textarea, etc.

The reportValidity method is the same and is available for the same tags. The only difference between them if the side effects. When we use the checkValidity method it will return a boolean (true if valid, false if not) without any side effect, but when we use the reportValidity we get the same boolean but at the same time the browser show the errors using the native browser way to do it (the same before we put the novalidate attribute).

How we can use it?

Having this HTML

<form id="my-super-form" novalidate>
<input type='text'
name='firstName'
id='firstName'
minlength='2'
pattern='[a-zA-Z]*'
required
/>
<button type="submit">Submit this form</button>
</form>

We could write this Javascript code

var form = document.querySelector("#my-super-form")
form.addEventListener("submit", (event) => {
event.preventDefault()
const isValid = form.checkValidity()
if (!isValid) {
return alert("the form is not valid")
}
const formData = new FormData(form)
// Do something with the formData, example send it via a ajax
})

This will end up with terrible user experience because the user will never know what is failing and what are the errors.

But the good thing is we can read the errors that the browser normally puts in there interface and use those in our advantage, and that can be done by using the property validationMessage this method is available for the inputs of the form, not the form itself. We have another property available to see the validation status of the input called validity and that returns an object like this one:

{
badInput: false
customError: false
patternMismatch: false
rangeOverflow: false
rangeUnderflow: false
stepMismatch: false
tooLong: false
tooShort: false
typeMismatch: false
valid: true
valueMissing: false
}

Describing if any type of error is there in order to categorize the errors if we need it.

We can access to those taking the elements of the Form and reading those properties, something like:

const submit = (event) => {
event.preventDefault()
const form = event.target
const isValid = form.checkValidity() // returns true or false
const formData = new FormData(form)
const validationMessages = Array
.from(formData.keys())
.reduce((acc, key) => {
acc[key] = form.elements[key].validationMessage
return acc
}, {})
console.log(validationMessages)
}

This will console something like:

{
"firstName": "Please fill out this field.",
"lastName": "Please fill out this field.",
"age": "Please fill out this field.",
"email": "Please fill out this field."
}

Now that we get a little bit more of how the native form validation works. Let's try to put that inside React

Here is the live example

I didn’t dig up too much in the React code because is almost the same that last post. But I’m using some hooks there to save the validation in order to print the validation errors.

I hope this information could be useful for you!

And if you want to see how we can create custom messages or something else using the same API, I created another example :)

Back to the code editor now :)

--

--