HTML5 form validation in React
Tags: react, validation, html5, components
Published: 2018-02-18 17:10:34

---
title: "HTML5 form validation in React"
published: true
tags: react,validation,html5,components
canonical_url: 
---

![](https://cdn-images-1.medium.com/max/1024/0*Hsjdj3i8TIc4_zrU.)<figcaption>“Colorful lines of code on a computer screen” by <a href="https://unsplash.com/@_imkiran?utm_source=medium&amp;utm_medium=referral">Sai Kiran Anagani</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption>

### Best data is a validated data

Users… Data collection… Forms… I’m sure you know that user input is good when it is valid ✅. That is why websites must encourage the users to fill in the best fitting data whenever possible.

There are various libraries like **jQuery Validation** or **Validate.js,** that help with form input validations. All of them implement the idea of performing predefined checks on each of the form fields before it is submitted. Then, they display error messages, if there are fields that do not qualify.

But there is also the powerful HTML5 validation API. And it’s awesome. Modern browsers almost fully support the API. Of course, each of them implemented its own way of performing the validation and displaying error messages. And sometimes it looks really nasty&nbsp;🙈

So, why not implement our own layout for the validation errors? Sounds doable. We will use the following aspects from the HTML5 constraint validation API: the **_checkValidity_** method and the&nbsp; **_:valid/:invalid_** states of a form, and the **_validity_** property of form elements. If curious, they are explained in detail in [this superb MDN Web Docs (Mozilla Developer Network) page.](https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation) What I am going to do is to implement custom validation messages using the API for a **React** app. Let’s go! 🏁&nbsp;🚗

### The React Component

Well, React means Components! We surely need to create one for this task. And, surprisingly, it will be a custom stateful **Form** component with its corresponding styles file.

First of all, let's define how we want to display our validation errors. I prefer to have separate messages next to each form field. For our ease, we will assume, that every input field is assigned with&nbsp; **_.form-control_** class, and each of them has a sibling \<_span\>_ with an&nbsp; **_.invalid-feedback_** class. Each span will hold the error message of its relevant form element. In this implementation, each form element will have its own error message container next to it. Of course, you are free to define your own error containers and even have only one container for displaying all of the messages in one place.

As you might already know, the validity of a form element is identified by a CSS pseudo class. If the element (_input, textarea, checkbox,…_) passes the defined rules, it is assigned with&nbsp; **_:valid_** pseudo class. Otherwise it gets&nbsp; **_:invalid_** pseudo class. We will use this behavior do decide whether an error message should be displayed next to an element or not. We’ll define a style in our **Form.css** that will hide the messages of valid elements.

```css
.form-control:valid~.invalid-feedback {display: none;}
```

The idea of the component is the following. In React, typically, we don’t want to reload the page on form submission. Instead, we want to send the data with **ajax** request. It doesn’t matter for our validation component how and what data is submitted. We just handle validation. That is why it will receive a property named **submit**, which is a function, that should be called whenever the form is allowed to be submitted. The component will override the native form submit event in the following way. First, it will check the overall form validity with the **_checkValidity_** method. If no errors found, it will perform the submission by calling the _submit_ method from **props.** If there was at least one invalid element, it will show the corresponding messages and cancel the form submission. And, of course, the component will render a regular _\<form\>_ tag, with all the child elements nested inside.

Sounds pretty straightforward, right? Let’s see how it looks like as a code&nbsp;😉

```javascript
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import './Form.css';

class Form extends Component {
    state = {
        isValidated: false
    }

    validate = () => {
        const formLength = this.formEl.length;

        if (this.formEl.checkValidity() === false) {
            for(let i=0; i<formLength; i++) {
                const elem = this.formEl[i];
                const errorLabel = elem.parentNode.querySelector('.invalid-feedback');

                if (errorLabel && elem.nodeName.toLowerCase() !== 'button') {
                    if (!elem.validity.valid) {
                        errorLabel.textContent = elem.validationMessage;
                    } else {
                        errorLabel.textContent = '';
                    }
                }
            }

            return false;
        } else {
            for(let i=0; i<formLength; i++) {
                const elem = this.formEl[i];
                const errorLabel = elem.parentNode.querySelector('.invalid-feedback');
                if (errorLabel && elem.nodeName.toLowerCase() !== 'button') {
                    errorLabel.textContent = '';
                }
            };

            return true;
        }
    }

    submitHandler = (event) => {
        event.preventDefault();

        if (this.validate()) {
            this.props.submit();
        }

        this.setState({isValidated: true});
    }

    render() {
        const props = [...this.props];

        let classNames = [];
        if (props.className) {
            classNames = [...props.className];
            delete props.className;
        }

        if (this.state.isValidated) {
            classNames.push('.was-validated');
        }

        return (
            <form ref={form => this.formEl = form} onSubmit={this.submitHandler} {...props} className={classNames} noValidate>
                {this.props.children}
            </form>
        );
    }
}

Form.propTypes = {
    children: PropTypes.node,
    className: PropTypes.string,
    submit: PropTypes.func.isRequired
};

export default Form;
```

Let’s dig into it starting from the bottom ⬆️. So, we render a regular _\<form\>_ that includes all the children passed to our component. It also gets a&nbsp; **.was-validated** class in case we have no errors. We can use this class for styling for example. We also hold a reference to our form element in our component. Thus we would be able to work with it with JavaScript methods. Also, we assign a _submit handler_ function to the form with the **_onSubmit_** event.

When the form is submitted (typically with a submit button), we call the component method called **_validate()._** It’s not hard to guess that this is the method where our component’s main functionality is hidden. So, if it returns **_true_**, the form is valid, and we are free to call the component’s **_submit_** method. Now, how does the validation work&nbsp;🤔?

#### The Validate&nbsp;method

In HTML5, a form validity is checked with the **_checkValidation()_** method. It returns **_true_** if all the form elements qualify defined rules and **_false_**, if at least one validation rule fails. We’ll use this behavior in our component.

In case the form is **valid**, we will loop through its elements and remove the text of their corresponding error containers.

If the form is invalid, we need to show messages for each of the erred elements. If a form element is invalid, its **_validity.valid_** property would be false. In such case, we will fill the&nbsp; **.invalid-feedback** _\<span\>_ with the corresponding error message. The error message provided by the API is accessible through the **_validationMessage_** property of an element. We will use that message as it is pretty much detailed and already localized with the browser locale. If you want to use your custom error messages, you should assign the _errorLabel.textContent_ with your value instead of _elem.validationMessage._ As simple as that.

Note, that we skip an element if it is a button. This is because a form refers to all of its elements that a user can interact with, including buttons.

Now, all our invalid fields have error messages next to them and our form is not submitted until all errors are fixed 👍 The only thing left to do is styling! But I guess I’ll leave the funny part to you, as _“I want to believe”_ (👽) in your creativity 😜

Thanks for reading this far, hope you had fun and learned something new here. 

Here is a full working [CodePen](https://codepen.io/_arpy/pen/xYoyPW) that I created as a playground 🎮 Enjoy, coders!

{% codepen https://codepen.io/_arpy/embed/xYoyPW/?height=505&theme-id=dark&default-tab=js,result&embed-version=2 %}

And one more thing…

### Secure yourself from both&nbsp;sides

Remember, validating user input in client side is not enough. A smarty like you can always find a way to avoid the validation. That is why **always** do checks also in your **backend.** Believe me, you’ll thank yourself for that&nbsp;☺️

![](https://media.giphy.com/media/u4KibgMsDLWM0/giphy.gif)