React form validation from scratch

Today we will learn about the React form validation.

Every application needs the user input and the input should be correct it is the developer responsibility. Here we need client side validation. Client-side validation is the process of checking that the values in your form’s input fields conform to certain expectations. Did the user fill out all the required fields? Is that an email address in the email field, or is it just gibberish? Is that comment too long or not long enough? Client-side validation improves the user experience by providing quick feedback, sometimes even before the user clicks ‘submit’. It also helps reduce server load and bandwidth by making fewer round trips.

So let’s get started React form validation

Live Demo

Create the React app

We’ll use create-react-app to get up and running quickly with a simple React app.

Install the package from npm and create a new app:

npm install -g create-react-app
create-react-app my-app

Adding Bootstrap in React

Next, let’s add bootstrap so that we can style our form easily:

npm install bootstrap --save

Import Bootstrap CSS and optionally Bootstrap theme CSS in the beginning of the src/index.js file:

import 'bootstrap/dist/css/bootstrap.min.css';

Create form:

Now let’s build the core of our demo app. Let’s create a login form. Open the src/App.js file and replace the default intro text with the below html

<div className="container">   
    <br />
    <div className="col-md-6 m-auto">
      <h3 className="mb-5">Login</h3> 
      <form onSubmit={this.submit} method="post">
          <div class="form-group">
            <label for="exampleInputEmail1">Email address</label>
            <input class="form-control" type="text" name="email" onKeyUp={this.changeHandler} placeholder="Enter email" />
            <small className="text-danger">{(this.state.formErrors.hasOwnProperty('email'))? this.state.formErrors.email[0] : ''}</small>
          </div>
          <div class="form-group">
            <label for="exampleInputPassword1">Password</label>
            <input type="password" name="password" class="form-control" onKeyUp={this.changeHandler} placeholder="Password" />
            <small className="text-danger">{(this.state.formErrors.hasOwnProperty('password'))? this.state.formErrors.password[0] : ''}</small>
          </div>
          
          <button type="submit" class="btn btn-primary">Submit</button>
      </form>
    </div>
</div>

Now, let’s initialise the state:

state =  {
    email: '',
    password: '',
    formErrors: {}
};

We need an onKeyUp handler for the input fields:

onKeyUp={this.changeHandler} 

which we’ll define as:

changeHandler = evt => {
	this.setState({
	  [evt.target.name] : evt.target.value
	});
}

changeHandler function will called on keyup and store input field value to the state

We need a onSubmit handler which will call a method when the form submit

which we’ll define as:

submit = (evt) => {
    
    evt.preventDefault();

    var response = ValidationService.validate({
		email: {
			value: this.state.email, 
			rules: {'required': true, 'validEmail': true } 
		},
		password: { 
			value: this.state.password, 
			rules: {'required': true, 'minLength': 5 } 
		}
    });

    this.setState({
      formErrors: (response)? response : {}
    });


    if(!response) {
      alert('It works!'); 
    }    
}

After the above changes our App.js file will looks like this

import React, { Component } from 'react';
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import ValidationService from "./services/ValidationService";

class App extends Component {
  state =  {
    email: '',
    password: '',
    formErrors: {}
  };

  
  submit = (evt) => {
    
    evt.preventDefault();

    var response = ValidationService.validate({
      email: { value: this.state.email, rules: {'required': true, 'validEmail': true } },
      password: { value: this.state.password, rules: {'required': true, 'minLength': 5 } }      
    });

    this.setState({
      formErrors: (response)? response : {}
    });


    if(!response) {
      alert('It works!');
    }
    
  }

  changeHandler = evt => {
    this.setState({
      [evt.target.name] : evt.target.value
    });
  }

  render() {

    return (
      <div className="container">   
        <br />
        <div className="col-md-6 m-auto">
          <h3 className="mb-5">Login</h3> 
          <form onSubmit={this.submit} method="post">
              <div class="form-group">
                <label for="exampleInputEmail1">Email address</label>
                <input class="form-control" type="text" name="email" onKeyUp={this.changeHandler} placeholder="Enter email" />
                <small className="text-danger">{(this.state.formErrors.hasOwnProperty('email'))? this.state.formErrors.email[0] : ''}</small>
              </div>
              <div class="form-group">
                <label for="exampleInputPassword1">Password</label>
                <input type="password"  name="password" class="form-control" onKeyUp={this.changeHandler} placeholder="Password" />
                <small className="text-danger">{(this.state.formErrors.hasOwnProperty('password'))? this.state.formErrors.password[0] : ''}</small>
              </div>
              
              <button type="submit" class="btn btn-primary">Submit</button>
          </form>
        </div>
      </div>
    );
  }
}


export default App;

Here you can see the ValidationService class which will validate our form. So let create ValidationService class.

Create ValidationService:

Create a ValidationService class and put the below code

const ValidationService = {
    messages: {},
    emailExpr: /^(([^<>()\[\]\\.,;:\[email protected]"]+(\.[^<>()\[\]\\.,;:\[email protected]"]+)*)|(".+"))@((\[[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,}))$/,
    required: function(field, value, param) {
        if(value.trim().length < 1) {
            if(ValidationService.messages.hasOwnProperty(field)) {
                if(ValidationService.messages[field].hasOwnProperty('required')){
                    return ValidationService.messages[field].required;
                }                
            }
            return 'This field is required';
        }
        return false;
    },
    validEmail: function(field, value, param) {
        
        if(!ValidationService.emailExpr.test(value)) {
            if(ValidationService.messages.hasOwnProperty(field)) {
                if(ValidationService.messages[field].hasOwnProperty('validEmail')){
                    return ValidationService.messages[field].validEmail;
                }                
            }
            return 'Invalid email';
        }
        return false;
    },
    minLength: function(field, value, param) {
        
        if(value.trim()) {            
            if(value.trim().length < param) {
                if(ValidationService.messages.hasOwnProperty(field)) {
                    if(ValidationService.messages[field].hasOwnProperty('minLength')){
                        return ValidationService.messages[field].minLength;
                    }                
                }
                return `This field must be minimum ${param} characters`;
            }
        }
        return false;
    },
    validate: function(options, messages) {
        ValidationService.messages = (messages)? messages : {};
        var errors = {}, error = [];
        Object.keys(options).forEach( field => {
            error = ValidationService.check(field, options[field].value, options[field].rules);
            if(error.length > 0) {
                errors[field] = error;
            }            
        })
        
        return Object.keys(errors).length < 1? null : errors;
    },

    check: function(field, value, methods) {
        return Object.keys(methods).map(item => {
            var error = ValidationService[item](field, value, methods[item]);
            return(error)? error : false;
        }).filter(item => { return(item); });
    }

};

export default ValidationService;

Here, I have created three validation rules.

  • required
  • validEmail
  • minLength

You can also create your custom rules. like below

const ValidationService = {
	yourCustomRules: function(field, value, param) {
		// your logic here
		return false
	}
}

You may also notice two methods in the ValidationService

  1. validate
  2. check

This will responsible to validate the form. You can modify according to your need

Change Error Message

Suppose you want change the message for the specific rules. you can achieve it by using the below methods

var response = ValidationService.validate({
  email: { 
  	value: this.state.email, 
  	rules: {'required': true, 'validEmail': true } 
  },
  password: { 
  	value: this.state.password, 
  	rules: {'required': true, 'minLength': 5 } 
  }
}, {
  email: {
    required: 'Test required'
  }
});

That’s it. Now your form validation is ready

Live Demo

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *