DEV Community

Cover image for React Real-time Form Validation Quick and Easy with js-flex-validator
CodeShipper
CodeShipper

Posted on

React Real-time Form Validation Quick and Easy with js-flex-validator

Validation is really important when it comes to frontend form implementation. You should never trust the user input, so you should validate that the information provided by the user is exactly what your application is expected.

There is a couple of libraries out there that help with form validation, but today I'll introduce a small and simple one called js-flex-validator, that allows you to quickly implement React form validation with real-time custom error messages.

First install the library using yarn or npm in your react project:

  • With npm
    npm install js-flex-validator

  • With yarn
    yarn add js-flex-validator

Now to show you how to use the library, we'll create a simple form like this one, with a username, email and password field:

See it live on CodeSandbox here

Image description

1- First, let's import the library Flex and the utility functions validateObject, validateValue from js-flex-validator:

import Flex, { validateObject, validateValue } from "js-flex-validator";
Enter fullscreen mode Exit fullscreen mode

2- Now, let's define the constraints for the username, email and password field of our form:

const constraints = {
  username: Flex("username")
    .string()
    .required()
    .allowEmpty()
    .min(3, "Username should be at least 3 characters")
    .max(50, "Username should not exceeds 50 characters"),

  email: Flex("email")
    .email("This email is not valid.")
    .match(/\w.@edu.com$/, "Should be an email with a edu.com domain")
    .required()
    .min(5, "Email should be at least 3 characters")
    .max(255, "Email should not exceeds 255 characters"),

  password: Flex("password")
    .string()
    .required()
    .min(8, "Password should be at least 8 characters")
    .max(20, "Password should not exceeds 20 characters")
    .match(
      /^(?=.*[A-Z])(?=.*[!@#$&*])(?=.*[0-9])(?=.*[a-z])/,
      "Should have at least 1 special character, 1 uppercase letter and 1 number"
    )
};
Enter fullscreen mode Exit fullscreen mode

3- Next, we define two functions, validateState and validateField. The validateState function is to validate our whole state object, that will have the username, email and password when the form is submitted. The validateField function is to validate each field individually as the user is filling the form.

const validateState = (state) => {
  const constraintsArr = Object.values(constraints);
  const { hasError } = validateObject(state, constraintsArr);
  return hasError;
};

const validateField = (name, value) => {
  const fieldConstraint = constraints[name];
  const message = validateValue(value, fieldConstraint);
  return message;
};
Enter fullscreen mode Exit fullscreen mode

4- Next, we implement our form (I assume you are familiar with react and know how to implement a form). For each input field, we make use of the validateField function, passing it the field value that we want to validate, and the constraint of this specific field, getting it from the constraints object that we defined earlier. Then we get the result of the validation, and set an errors object, if there is an error.

Then when the form is submitted, we make use of the validateState function to make sure that all fields are valid, before submitting the form.

const initialState = { 
  username: "", 
  password: "", 
  email: "" 
};

export default function App() {
  const [state, setState] = React.useState(initialState);
  const [errors, setErrors] = React.useState(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    // Validate if all fields in the state are valid, if not, return. 
    const error = validateState(state);
    if (error) return;

    // If all fields are valid, process the data
    console.log(state);
  };

  const handleChange = (e) => {
    const { name, value } = e.target;
    // set state, with the value entered by the user
    setState({ 
      ...state, 
     [name]: value.trim() 
    });
    // check if value entered by user is valid
    const fieldError = validateField(name, value.trim());
    // Set errors if any
    if(fieldError){
       setErrors({ 
        ...errors, 
        [name]: fieldError
       });
    }
  };

  return (
    <form className="App" onSubmit={handleSubmit}>
      <h2>React Form Validation</h2>
      <h4>With JS-flex-validator</h4>

      <div>
        <input
          name="username"
          type="text"
          placeholder="Username"
          value={state.username}
          onChange={handleChange}
        />
        {errors && <small>{errors.username}</small>}
      </div>

      <div>
        <input
          name="email"
          type="text"
          placeholder="Email"
          value={state.email}
          onChange={handleChange}
        />
        {errors && <small>{errors.email}</small>}
      </div>

      <div>
        <input
          name="password"
          type="password"
          placeholder="Password"
          value={state.password}
          onChange={handleChange}
        />
        {errors && <small>{errors.password}</small>}
      </div>

      <div>
        <button disabled={validateState(state)} type="submit">
          submit
        </button>
      </div>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here is the full and simplified code, that implements the real-time validation using js-flex-validator

import React from "react";
import Flex, { validateObject, validateValue } from "js-flex-validator";
import "./styles.css";

const constraints = {
  username: Flex("username")
    .string()
    .required()
    .allowEmpty()
    .min(3, "Username should be at least 3 characters")
    .max(50, "Username should not exceeds 50 characters"),

  email: Flex("email")
    .email("This email is not valid.")
    .match(/\w.@edu.com$/, "Should be an email with a edu.com domain")
    .required()
    .min(5, "Email should be at least 3 characters")
    .max(255, "Email should not exceeds 255 characters"),

  password: Flex("password")
    .string()
    .required()
    .min(8, "Password should be at least 8 characters")
    .max(20, "Password should not exceeds 20 characters")
    .match(
      /^(?=.*[A-Z])(?=.*[!@#$&*])(?=.*[0-9])(?=.*[a-z])/,
      "Should have at least 1 special character, 1 uppercase letter and 1 number"
    )
};

const validateState = (state) => {
  const constraintsArr = Object.values(constraints);
  const { hasError } = validateObject(state, constraintsArr);
  return hasError;
};

const validateField = (name, value) => {
  const fieldConstraint = constraints[name];
  const message = validateValue(value, fieldConstraint);
  return message;
};

const initialState = { username: "", password: "", email: "" };

export default function App() {
  const [state, setState] = React.useState(initialState);
  const [errors, setErrors] = React.useState(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    const error = validateState(state);
    if (error) return;
    console.log(state);
  };

  const handleChange = (e) => {
    const { name, value } = e.target;
    setState({ ...state, [name]: value.trim() });
    setErrors({ ...errors, [name]: validateField(name, value.trim()) });
  };

  return (
    <form className="App" onSubmit={handleSubmit}>
      <h2>React Form Validation</h2>
      <h4>With JS-flex-validator</h4>

      <div>
        <input
          name="username"
          type="text"
          placeholder="Username"
          value={state.username}
          onChange={handleChange}
        />
        {errors && <small>{errors.username}</small>}
      </div>

      <div>
        <input
          name="email"
          type="text"
          placeholder="Email"
          value={state.email}
          onChange={handleChange}
        />
        {errors && <small>{errors.email}</small>}
      </div>

      <div>
        <input
          name="password"
          type="password"
          placeholder="Password"
          value={state.password}
          onChange={handleChange}
        />
        {errors && <small>{errors.password}</small>}
      </div>

      <div>
        <button disabled={validateState(state)} type="submit">
          submit
        </button>
      </div>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

Hope this helps.

Happy coding!

Top comments (0)