This is a step-by-step tutorial that will show you how to do basic form validation in React.
You can see the full code on Github and see the app running on Heroku.
learnetto/react-form-validation-demo_react-form-validation-demo - React Form Validation Demo_github.com
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 react-form-validation-demo
Now letâs run the app:
$ cd react-form-validation-demo/$ npm start
That opens http://localhost:3000/ where our new app is running.
Next, letâs add bootstrap so that we can style our form easily:
$ npm install react-bootstrap â save$ npm install bootstrap@3 â save
Import Bootstrap CSS and optionally Bootstrap theme CSS in the beginning of the src/index.js file:
import âbootstrap/dist/css/bootstrap.cssâ;import âbootstrap/dist/css/bootstrap-theme.cssâ;
Ok, now letâs build the core of our demo app. Letâs add a Form component.
In src/App.js, letâs replace the default intro text markup with a Form component that weâre going to build. We also need to import it:
import React, { Component } from 'react';import logo from './logo.svg';import './App.css';import Form from './Form.js';
class App extends Component {render() {return (<div className="App"><div className="App-header"><img src={logo} className="App-logo" alt="logo" /><h2>React Form Validation Demo</h2></div><Form /></div>);}}
export default App;
Now, letâs create that Form component in src/Form.js.
Weâll make a simple sign up form with email and password input fields and a submit button.
import React, { Component } from âreactâ;import â./Form.cssâ;
class Form extends Component {render () {return (<form className=âdemoFormâ><h2>Sign up</h2><div className=âform-groupâ><label htmlFor=âemailâ>Email address</label><input type=âemailâ className=âform-controlâname=âemailâ /></div><div className=âform-groupâ><label htmlFor=âpasswordâ>Password</label><input type=âpasswordâ className=âform-controlâname=âpasswordâ /></div><button type=âsubmitâ className=âbtn btn-primaryâ>Sign up</button></form>)}}export default Form;
Iâve copied an example form from the Bootstrap docs so that it looks nice out of the box.
But notice I had to change some things to make it work with JSX.
class and for are reserved keywords in JavaScript, so we have to use className and htmlFor instead respectively.
We also need to make sure we close all tags including the input tag.
Now, letâs initialise the state in the constructor:
constructor (props) {super(props);this.state = {email: '',password: ''}}
Weâre setting email and password to empty strings.
Weâll hook up the form input fields to these state values, for email:
value={this.state.email}
and for password:
value={this.state.password}
But weâre not updating the state on user input, so if we type in the form fields now, our text wonât appear.
We need an onChange handler for the input fields:
onChange={this.handleUserInput}
which weâll define as:
handleUserInput = (e) => {const name = e.target.name;const value = e.target.value;this.setState({[name]: value});}
Ok, now letâs get to the validation.
Weâll save any validation errors and the validity status of the form in the state.
So letâs add couple of properties to our initial state:
constructor (props) {super(props);this.state = {email: '',password: '',formErrors: {email: '', password: ''},emailValid: false,passwordValid: false,formValid: false}}
Weâre adding a property called formErrors which will be an object with the input field names as keys and any validation errors as their values. The initial value for each key is an empty string.
We also have 3 boolean propertiesâââemailValid, passwordValid and formValid, which weâll use to enable or disable the form submit button, based on our validation results. We set their initial values to false.Now letâs add a new component called FormErrors for displaying any errors from our validation above the form.
<div className=âpanel panel-defaultâ><FormErrors formErrors={this.state.formErrors} /></div>
Weâll save it in src/FormErrors.js:
import React from âreactâ;
export const FormErrors = ({formErrors}) =><div className='formErrors'>{Object.keys(formErrors).map((fieldName, i) => {if(formErrors[fieldName].length > 0){return (<p key={i}>{fieldName} {formErrors[fieldName]}</p>)} else {return '';}})}</div>
Itâs a stateless functional component (or presentational component) which simply iterates through all the form validation errors and displays them.
Now, weâll call a validation after the user types in the field.
The setState method accepts a callback function as a second argument, so letâs pass a validation function to it.
handleUserInput (e) {const name = e.target.name;const value = e.target.value;this.setState({[name]: value},() => { this.validateField(name, value) });}
Letâs define that:
validateField(fieldName, value) {let fieldValidationErrors = this.state.formErrors;let emailValid = this.state.emailValid;let passwordValid = this.state.passwordValid;
switch(fieldName) {case 'email':emailValid = value.match(/^([\w.%+-]+)@([\w-]+\.)+([\w]{2,})$/i);fieldValidationErrors.email = emailValid ? '' : ' is invalid';break;case 'password':passwordValid = value.length >= 6;fieldValidationErrors.password = passwordValid ? '': ' is too short';break;default:break;}this.setState({formErrors: fieldValidationErrors,emailValid: emailValid,passwordValid: passwordValid}, this.validateForm);}
validateForm() {this.setState({formValid: this.state.emailValid &&this.state.passwordValid});}
We do two different checks for the input fields. For the email field, we check it against a regular expression to see if itâs an email.
Note: Iâm using an example regex from the Devise library. Checking for emails with a regex is very complex, but this simple regex will do for our toy app.
For the password field, we check if the length is a minimum of 6 characters or not.
When the field doesnât pass the check, we set an error message for it and set its validity to false.
Then we call setState to update the formErrors and the field validity and we pass the validateForm callback to set the value of formValid.
Letâs set the disabled attribute of the submit button based on the value of the formValid state property.
<button type="submit" className="btn btn-primary"disabled={!this.state.formValid}>Sign up</button>
So with that, our basic form validation works.
We can add one little enhancement by highlighting the input fields when they have an error.
Weâll add the bootstrap has-error class to a fieldâs form-group based on its error value:
<div className={`form-group${this.errorClass(this.state.formErrors.email)}`}>
errorClass is a method we can define as:
errorClass(error) {return(error.length === 0 ? '' : 'has-error');}
Now when a field has an error, it has a red border around it.
And thatsâ all for this tutorial.
You can see the full code on Github and the demo app running on Heroku.
This is a very simple example. We have hard-coded field names in our validation code, which is not ideal or scalable. We can also only have one validation per field, which is also not practical.
But we can generalise it to handle any number of fields with multiple errors.
There are many libraries available for form validations, but before you start using them, itâs good to think about how youâd implement the functionality yourself.
This tutorial is an excerpt form Module 6 of The FREE Complete React on Rails Course, in which I cover form validations in a lot more depth. Check it out.
The Complete React on Rails 5 Course_PRE-ORDERS ARE OPEN! This course is open for pre-orders. The first 6 modules are live. New lessons will be publishedâŚ_learnetto.com
Originally published at learnetto.com.