Best ReactJS Form library for 2024

form

As our application gets bigger and more complicated, it can be worth to look a third-party library.  React third-party libraries helps you to reduce boilerplate, standardize our code, and simplify complex problems.

Most React applications contain forms. Forms are used to collect data for processing from users. If you are building a React application that contains one or more forms.  If you work with React, you know that it provides a way to handle forms using controlled components. However, it can become tedious with a lot of repetitive code if you build a lot of forms, and you may want to also validate and keep track of the visited fields or form state. To solve this problem a form library is used that helps easy to build forms of varying complexity, with validation and state management.

Why we need ReactJS form library?

A library is used to make development work easier. If you are writing repetitive code with complex validation logic, think about installing the form library. If the most complex form in your application is your login or registration form, then you probably don’t need to use a third-party form library.

In this article, we will find some best react form the library, which you can use.

Formik

formik ReactJS Form library

Formik is one of the most popular form libraries in react. It allows you to easily build complex forms, and it works nicely with yup validation.

Formik helps you with managing the form state, handling submission, formatting, and validating form values. It’s also quite small in size. It is 13.1 kB when gzipped and minified, with support for TypeScript, and works with React Native.

f

Here is a code for writing a form to collect user data with Formik:

import { Formik, Form, Field, ErrorMessage } from "formik";

const DataForm = () => (
  <>
    <h1>Your Data</h1>
    <Formik
      initialValues={{ name: "", email: "", acceptedTerms: false }}
      validate={(values) => {
        const errors = {};
        if (!values.name) {
          errors.name = "Required";
        }

        if (!values.acceptedTerms) {
          errors.acceptedTerms =
            "You must accept the terms and conditions before you proceed.";
        }

        if (!values.email) {
          errors.email = "Required";
        } else if (
          !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
        ) {
          errors.email = "Invalid email address";
        }
        return errors;
      }}
      onSubmit={(values, { setSubmitting }) => {
        // post data to server
        alert(JSON.stringify(values, null, 2));
        setSubmitting(false);
      }}
    >
      {({ isSubmitting, dirty, handleReset }) => (
        <Form>
          <div>
            <label>
              Name
              <Field type="text" name="name" />
            </label>
            <ErrorMessage name="name" component="span" />
          </div>
          <div>
            <label htmlFor="email">Email</label>
            <Field type="email" name="email" />
            <ErrorMessage name="email" component="span" />
          </div>
          <div>
            <label>Accept terms</label>
            <Field type="checkbox" name="acceptedTerms" />
            <ErrorMessage name="acceptedTerms" component="span" />
          </div>
          <button
            type="button"
            onClick={handleReset}
            disabled={!dirty || isSubmitting}
          >
            Reset
          </button>
          <button type="submit" disabled={isSubmitting}>
            Submit
          </button>
        </Form>
      )}
    </Formik>
  </>
);

export default DataForm;

Formik comes with components that make it easier to manage the form state and then expose the form data via props. You wrap the form with the <Formik /> component and pass it props.

One of the best things about formic is its code is simple, it’s easy to manually manipulate other field values.

React hook form

hook

As the name suggests it was built post React hooks release and is really optimize form them and written in typescript,  it will also make you write a little less code than the other two libraries especially for validation which is always a good thing.

f

It is a flexible library that embraces the hooks API and uncontrolled components. It is open source and has 17.3k GitHub stars, and it’s 9.1kB when gzipped and minified. It supports typescript and react native, but unlike the others, there’s no component to wrap your form. You will use the useForm hook it provides to access form state. Let’s look at an example.

import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit, errors, reset, formState } = useForm();
  const { isDirty, isSubmitting } = formState;

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <h1> Your Data</h1>
      <div>
        <label>Name</label>
        <input
          type="text"
          placeholder="Full Name"
          name="name"
          ref={register({ required: "Name Required " })}
        />
        <span>{errors.name?.message}</span>
      </div>
      <div>
        <label>Email</label>
        <input
          type="text"
          placeholder="Email"
          name="email"
          ref={register({
            required: "Email Required",
            pattern: { value: /^\S+@\S+$/i, message: "Invalid email address" },
          })}
        />
        <span>{errors.email?.message}</span>
      </div>
      <div>
        <label>Accept Terms</label>
        <input
          type="checkbox"
          placeholder="Accept Terms"
          name="acceptedTerms"
          ref={register({ required: true })}
        />
        {errors.acceptedTerms && <span>You must accepet the terms</span>}
      </div>

      <button type="button" onClick={reset} disabled={!isDirty || isSubmitting}>
        Reset
      </button>
      <input type="submit" disabled={isSubmitting} />
    </form>
  );
}

To use this library call the useform() hook which will return objects and functions to manage the form state.

The handleSubmit function will be called when the form is submitting. It accepts two functions as arguments: the first one will be called with the form data if the form validation is successful, and the second one will be called when the validation fails.

The register function allows you to register an input/select element Ref and supply validation rules as well. You can specify the error message for a validation rule when it is defined or skip it. you can install the @hookform/error-message package. With it, you can use it to display the error message for name and email as follows:

import { ErrorMessage } from "@hookform/error-message";
// other necessary code ...
<ErrorMessage errors={errors} name="name" />

<ErrorMessage
  errors={errors}
  name="email"
  render={({ message }) => <p>{message}</p>}
/>

React-Final-Form

final ReactJS Form library

React Final Form is a subscription-based form state management library based on Final Form. It is built by the same author as redux form. It uses the Observer pattern so that only the components that need updating are re-rendered as the form’s state changes. By default, it subscribes to all changes, but if you want to optimize for blazing-fast perfection, you may specify only the form state that you care about.

fo

Let’s look at the syntax for using Final Form.

import { Form, Field } from "react-final-form";

const DataForm = () => (
  <>
    <h1>Your Data</h1>
    <Form
      onSubmit={(values) => alert(JSON.stringify(values, 0, 2))}
      initialValues={{ acceptedTerms: true }}
      validate={(values) => {
        const errors = {};
        if (!values.name) {
          errors.name = "Required";
        }

        if (!values.acceptedTerms) {
          errors.acceptedTerms =
            "You must accept the terms and conditions before you proceed.";
        }

        if (!values.email) {
          errors.email = "Required";
        } else if (
          !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
        ) {
          errors.email = "Invalid email address";
        }
        return errors;
      }}
      render={({
        handleSubmit,
        form,
        submitting,
        pristine,
        values,
        errors,
        touched,
      }) => (
        <form onSubmit={handleSubmit}>
          <Field name="name">
            {({ input, meta }) => (
              <div>
                <label>Username</label>
                <input {...input} type="text" placeholder="Username" />
                {meta.error && meta.touched && <span>{meta.error}</span>}
              </div>
            )}
          </Field>
          <div>
            <label>Twitter Handle</label>
            <Field name="twitter" component="input" type="text" />
          </div>
          <Field name="email">
            {({ input, meta }) => (
              <div>
                <label>Email</label>
                <input {...input} type="email" />
                {meta.error && meta.touched && <span>{meta.error}</span>}
              </div>
            )}
          </Field>
          <div>
            <label>Accept Terms</label>
            <Field name="acceptedTerms" component="input" type="checkbox" />
            {touched.acceptedTerms && errors.acceptedTerms && (
              <span>{errors.acceptedTerms}</span>
            )}
          </div>
          <div>
            <button
              type="button"
              onClick={form.reset}
              disabled={submitting || pristine}
            >
              Reset
            </button>
            <button type="submit" disabled={submitting}>
              Submit
            </button>
          </div>
        </form>
      )}
    />
  </>
);

export default DataForm;

react form uses two components 1) <Form />

2) <Field />

The <Form /> component is a wrapper over the HTML form and it manages the form state and events.

You can set initial values to use for initializing the form state, the submit handler and validate prop for form-level validation.

You can also do field-level validation bypassing validation props to the <Field /> component.

The <Field /> component registers a field with the form, subscribes to the field state, and injects both field state and callback functions (onBlur, onChange, and onFocus) via rendering prop.

The <Field /> component registers a field with the form, subscribes to the field state, and injects both field state and callback functions (onBlur, onChange, and onFocus) via rendering prop.

It is maintained by Erik Rasmussen, who also built Redux Form. It is open source and has 6.3k GitHub stars, weighing 3.2 kB when gzipped and modified, plus 5.4 kB gzipped for Final Form.

Unlike Formik and React Hook Form, it doesn’t have an <ErrorMessage /> component. However, you can easily build one that can be reused in your project using the useField hook.

import { useField } from "react-final-form";

const ErrorMessage = ({ name }) => {
  const {
    meta: { error, touched },
  } = useField(name, { subscription: { error: true, touched: true } });
  return error && touched ? <span>{error}</span> : null;
};

Conclusion

Every react form library listed is fast and helps you build and manage complex forms. Any of the libraries you choose must be useful in your project.

Check more articles –