React Real-time Form Validation Quick and Easy with js-flex-validator
Tags: react, javascript, beginners, programming
Published: 2022-12-01 03:25:49

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](https://codesandbox.io/s/react-form-validation-with-flex-validator-0ikdp?file=/src/App.js)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02a0nv6joojsslqnzccl.png)


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


```js
import Flex, { validateObject, validateValue } from "js-flex-validator";
```

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

```js
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"
    )
};
```

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.

```js
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;
};
```

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.

```js
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>
  );
}
```

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

```js
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>
  );
}
```

Hope this helps.

Happy coding!