Top 4 best React form validation libraries (2023)

Last updated on January 4, 2023 Guest Contributor Loading... Post a comment

Form validation is an important part of many web and mobile applications. In React, you can write the validation logic on your own, but if you’re working on a production project, this job can cost much time and effort for coding, testing, fixing bugs, etc. Thankfully, there are lots of open-source libraries made by the community that can help us get the matter done neatly and quickly so that you can have more time to think and build your big things. One problem is that not all of these libraries are good enough. Some of them used to be nice but are no longer maintained and have become outdated.

In this article, we will cover 4 of the best React form validation libraries for 2023 and the years to come.

Formik

Formik is one of the most popular React form libraries at this time. It takes care of keeping track of values/errors/visited fields, orchestrating validation, and handling submissions. There are no fancy subscriptions or observables under the hood, just plain React state and props. By staying within the core React framework and away from magic, the library makes debugging, testing, and reasoning about your forms a breeze.

In addition, Formik does NOT use external state management libraries like Redux or MobX. This also makes Formik easy to adopt incrementally and keeps bundle size to a minimum.

Sample code (Javascript):

import React from "react";
import ReactDOM from "react-dom";
import { Formik, Field, Form } from "formik";

function App() {
  return (
    <div className="App">
      <h1>Contact Us</h1>
      <Formik
        initialValues={{ name: "", email: "" }}
        onSubmit={async values => {
          await new Promise(resolve => setTimeout(resolve, 500));
          alert(JSON.stringify(values, null, 2));
        }}
      >
        <Form>
          <Field name="name" type="text" />
          <Field name="email" type="email" />
          <button type="submit">Submit</button>
        </Form>
      </Formik>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

One more example (Typescript):

import 'react-app-polyfill/ie11';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Formik, Field, Form, FormikHelpers } from 'formik';

interface Values {
  firstName: string;
  lastName: string;
  email: string;
}

const App = () => {
  return (
    <div>
      <h1>Signup</h1>
      <Formik
        initialValues={{
          firstName: '',
          lastName: '',
          email: '',
        }}
        onSubmit={(
          values: Values,
          { setSubmitting }: FormikHelpers<Values>
        ) => {
          setTimeout(() => {
            alert(JSON.stringify(values, null, 2));
            setSubmitting(false);
          }, 500);
        }}
      >
        <Form>
          <label htmlFor="firstName">First Name</label>
          <Field id="firstName" name="firstName" placeholder="John" />

          <label htmlFor="lastName">Last Name</label>
          <Field id="lastName" name="lastName" placeholder="Doe" />

          <label htmlFor="email">Email</label>
          <Field
            id="email"
            name="email"
            placeholder="[email protected]"
            type="email"
          />

          <button type="submit">Submit</button>
        </Form>
      </Formik>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

react-hook-form

This lib is the winner of the 2020 GitNation React OS Award for Productivity Booster. It provides an intuitive, feature-complete API providing a seamless experience to developers when building forms. It is good at performance because of minimizing the number of re-renders. Since the form state is inherently local, it can be easily adopted without other dependencies.

Sample code (Javascript):

import * as React from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm();

  const onSubmit = (data) => alert(JSON.stringify(data));

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register} placeholder="First name" />

      <input name="lastName" ref={register} placeholder="Last name" />

      <select name="category" ref={register}>
        <option value="">Select...</option>
        <option value="A">Category A</option>
        <option value="B">Category B</option>
      </select>

      <input type="submit" />
    </form>
  );
}

react-form

This one is built with React hooks and is used for functional components. It offers flexible form API at the field, scope, and form levels, built-in validation debouncing with auto cancellation for stale validations, etc.

The library hasn’t been updated for quite some time. You should consider it carefully if you plan to use it.

Sample usage:

import { useForm, useField, splitFormProps } from "react-form";

async function sendToFakeServer(values) {
  await new Promise(resolve => setTimeout(resolve, 1000));
  return values;
}

function validateAddressStreet(value) {
  if (!value) {
    return "A street is required";
  }
  return false;
}

async function fakeCheckValidName(name, instance) {
  if (!name) {
    return "A name is required";
  }

  return instance.debounce(async () => {
    console.log("checking name");
    await new Promise(resolve => setTimeout(resolve, 1000));
    // All names are valid, so return a false error
    return false;
  }, 500);
}

const InputField = React.forwardRef((props, ref) => {
  // Let's use splitFormProps to get form-specific props
  const [field, fieldOptions, rest] = splitFormProps(props);

  // Use the useField hook with a field and field options
  // to access field state
  const {
    meta: { error, isTouched, isValidating },
    getInputProps
  } = useField(field, fieldOptions);

  // Build the field
  return (
    <>
      <input {...getInputProps({ ref, ...rest })} />{" "}
      {isValidating ? (
        <em>Validating...</em>
      ) : isTouched && error ? (
        <em>{error}</em>
      ) : null}
    </>
  );
});

function MyForm() {
  // Use the useForm hook to create a form instance
  const {
    Form,
    meta: { isSubmitting, canSubmit }
  } = useForm({
    onSubmit: async (values, instance) => {
      // onSubmit (and everything else in React Form)
      // has async support out-of-the-box
      await sendToFakeServer(values);
      console.log("Huzzah!");
    },
    debugForm: true
  });

  return (
    <Form>
      <div>
        <label>
          Name: <InputField field="name" validate={fakeCheckValidName} />
        </label>
      </div>
      <div>
        <label>
          Address Street:{" "}
          <InputField field="address.street" validate={validateAddressStreet} />
        </label>
      </div>

      <div>
        <button type="submit" disabled={!canSubmit}>
          Submit
        </button>
      </div>

      <div>
        <em>{isSubmitting ? "Submitting..." : null}</em>
      </div>
    </Form>
  );
}

function App() {
  return <MyForm />;
}

formsy-react

formsy-react helps you build any kind of form element components as well as add validation rules and use them with simple syntax. You can also use handlers for different states of your form like onSubmit, onValid, etc.

Sample code (class-based component):

// MyInput.js
import { withFormsy } from 'formsy-react';
import React from 'react';

class MyInput extends React.Component {
  constructor(props) {
    super(props);
    this.changeValue = this.changeValue.bind(this);
  }

  changeValue(event) {
    // setValue() will set the value of the component, which in
    // turn will validate it and the rest of the form
    // Important: Don't skip this step. This pattern is required
    // for Formsy to work.
    this.props.setValue(event.currentTarget.value);
  }

  render() {
    // An error message is passed only if the component is invalid
    const errorMessage = this.props.errorMessage;

    return (
      <div>
        <input onChange={this.changeValue} type="text" value={this.props.value || ''} />
        <span>{errorMessage}</span>
      </div>
    );
  }
}

export default withFormsy(MyInput);

Conclusion

Form validation on the client side doesn’t guarantee your application will be completely secure because some suspicious users can tweak your code with their browsers (Chrome DevTools, for example). However, as a React developer, validation is a part that cannot be ignored because it will greatly limit unnecessary requests to the server, improve user experience and help your app be more professional.

If you would like to explore more about React, read also these articles:

You can also check our React topic page and Next.js topic page for the latest tutorials and examples.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

Related Articles