DEV Community

Cover image for React Forms — Formik vs. Hook-Form vs. Final-Form
Sm0ke
Sm0ke

Posted on • Updated on • Originally published at blog.appseed.us

React Forms — Formik vs. Hook-Form vs. Final-Form

Hello Coders!

Forms are a crucial part of every application, from signing up, logging in, or collecting a survey from our users. Forms may seem simple but they are not. This article aims to provide a comparison of the top most-used React Forms with pros, cons, and code samples: Formik, React-Hook-Form and React-Final-Form. For newcomers, React is a super popular JS library for coding interactive user interfaces baked by Facebook.


Here are the topics covered in this material:

  • ✅ Why do we need forms?
  • ✅ Intro to React (a short one)
  • Formik: pros, cons, and sample
  • React-Hook-Form: pros, cons, and sample
  • React-Final-Form: pros, cons, and sample
  • ✅ Conclusions & Resources
  • ✅ Free React Sample: Berry (use Formik)
  • ✅ Free React Sample: Datta Able (use Formik)

PROMO 🚀 SeRanking - All-in-one SEO Software

Award-winning SEO Tool for your business - Pricing starts from $25/mo.

  • 100% accurate keyword rank tracking
  • ✅ In-depth website audit
  • Backlink checking & monitoring
  • ✅ Keyword Research

SeRanking - All-in-one SEO software made simple (service banner)


✨ Why do we need forms

As mentioned above, forms might seem trivial and easy to code, but this fact is not true in all cases. Forms require validating the information provided by the user and coding multiple forms in different parts of our projects might be time-consuming. To solve this problem, we can use Form Libraries built on top of React released in the open-source ecosystem like Formik or `React- Final Form.

All mentioned libraries are easy to use and have (almost) all the functionalities we might need in our projects.

All we have to do is install and perform a quick setup of our preferred library. After that, we should be able to code much faster all forms required in the project and spend more time developing the actual business logic for the app.


✨ What is React

React is an open-source UI library, built and maintained by Facebook. React breaks down a big application into smaller pieces called components. This component-based approach of React makes it more usable and maintainable.

As you’ll see React is not a framework it’s a library. That means it’s not a complete solution.

New to React? Check out this comprehensive React Starting Guide


JavaScript & React — Getting Starting Guide.


When you build an application with react you’ll need to use other external libraries to finish the application. This approach of React makes it more powerful because you have the freedom to choose whatever library you want for your app.

Examples of the libraries you might need to use are Axios for HTTP requests, Redux for managing states, and React-router-dom for Routing, React-hook-form for building forms.


✨ Why choose the right Form Library?

Might be important what form library you choose for your application because some libraries are large and slow, and a lot of boilerplate codes or lack of support. These issues make using the library difficult.
For these reasons you have to be picky about the library you choose for your application. So, without any delay let’s dive in and see the pros and cons of the top three React Form Libraries.

We’ll start with Formik.


✨ Formik

Formik is an open-source React form library Authored by Jared Palmar. Jared built Formik out of frustration when he had to build more than 30 forms for his application. He wanted a standard way to build and manage all the forms in his application. For this he built Formik.

Open-Source React Form — Formik.


This library helps you with the three most annoying but important parts of building forms:

  • 👉 Getting values in and out of form state
  • 👉 Validation and error messages
  • 👉 Handling form submission

You can build a form easily with Formik’s <Formik />, <Form />, <Field />, and <ErrorMessage /> components. Building a form with Formik is super easy. Later In this section, I’ll show you how to build a form and validate it with Formik.
Before that let’s look at a few pros and cons of Formik.


Formik Pros

  • Declarative components (, , )
  • 29k+ stars on Github
  • Integration with popular validation library: Yup
  • External UI Library support.

Formik Cons

  • 7 dependencies and 12.7 kB in size
  • 500+ Issues on GH
  • No built-in validation
  • A lot of boilerplate code (compared to React-hook-form)

Now that we’ve seen the pros and cons of Formik, let’s build a simple form with `Formik to make it clear.


Install Formik

To build a form with Formik first we’ll have to install it. We can do that with these commands:

$ npm install formik
// OR
$ yarn add formik
Enter fullscreen mode Exit fullscreen mode

Form Source Code

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

const Basic = () => (
  <div>
    <h1>Sign Up</h1>
    <Formik
      initialValues={{
        firstName: '',
        lastName: '',
        email: '',
      }}
      onSubmit={async (values) => {
        await new Promise((r) => setTimeout(r, 500));
        alert(JSON.stringify(values, null, 2));
      }}
    >
      <Form>
        <label htmlFor="firstName">First Name</label>
        <Field id="firstName" name="firstName" placeholder="Jane" />

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

        <label htmlFor="email">Email</label>
        <Field
          id="email"
          name="email"
          placeholder="jane@acme.com"
          type="email"
        />
        <button type="submit">Submit</button>
      </Form>
    </Formik>
  </div>
);

ReactDOM.render(<Basic />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

As you can see it’s a simple form. We didn’t add validation yet. I’ll do that in the next section.

To build the Form we called the <Formik> component. It takes two props: initialValues object which defines the initial values of the input fields and onSubmit method which handles form submission.

As you noticed, this form is self-declarative. That means the code describes what’s going on. you don’t need much effort to understand it.

Once we have finished the basic form, the next step is to add validation and constraint user to input relevant information.


👉 Form Validation in Formik

One of the reasons to build Formik is to make form validation hassle-free. Formik supports synchronous and asynchronous Form-level and Field-level validation. It also provides schema-based Form-level validation through Yup. Yup is a very popular form validation library.

  • 👉 Form-level validation
  • 👉 Field-level validation

This is it. A complete Form built with Formik. For more resources, feel free to access:


✨ React Hook Form

React-Hook-Form is a form library built around React hooks. This library takes a different approach to building Form. It isolates component re-renders by using uncontrolled components.

Unlike Formik, React-Hook-Form has zero dependencies. And the size is half the size of Formik ~= 8.6KB (minified + gzipped).

React Hook Form — Open-Source Library.


React Hook Form reduces the amount of code you need to write while removing unnecessary re-renders. To validate forms React-hook-form uses the standard Html based approach. You can build a form with React-hook-form easily with the useForm hook. I’ll show you how to do that later in the post.

But now let’s look at a few Pros and Cons of React Hook Form.


React-Hook-Form Pros

  • Less boilerplate code, Zero dependency
  • No issues on Github (what?)
  • 8.6kb size (minified and gzipped)
  • Out-of-the-box integration with UI libraries
  • Embraces native HTML form validation
  • Support’s Yup form validation.

React-Hook-Form Cons

  • You need to use Yup or Built-in form validation

Install React-Hook-Form

$ npm install react-hook-form
// OR
$ npm install react-hook-form 
Enter fullscreen mode Exit fullscreen mode

React-Hook-Form — Sample

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

const HookForm = () => {
    const { register, handleSubmit } = useForm();
    const handleRegistration = (data) => console.log(data);

    return (
      <div>
        Hook Form
    <form onSubmit={handleSubmit(handleRegistration)}>
      <div>
        <label>Email</label>
        <input type="email" name="email" {..register('email')} />
       </div>
       <div>
          <label>Password</label>
          <input type="password" name="pass" {..register('pass')} />
        </div>
        <button>Submit</button>
    </form>
      </div>
    );
};
Enter fullscreen mode Exit fullscreen mode

The handleSubmit handles the form submission and the register method helps you register an input field into React Hook Form so that it is available for validation, and its value can be tracked for changes.
This is a basic form. Now let’s look at how you can validate forms with react-hook-form:


Form validation in React-Hook-Form

React Hook Form uses native HTML form validation to validate forms. To validate using you pass the validation rules to the register method.

The validation rules are:

  • required: indicates if the field is required or not.
  • minlength and maxlength set the minimum and maximum length for a string input value
  • min and max set the minimum and maximum values for a numerical value
  • pattern: takes a regular expression pattern to test the input.

Here’s an example of how you validate forms in React-hook-form:

export default function App() {    
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {..register("firstName", { required: true, maxLength: 20 })} />
      <input {..register("lastName" , { pattern: /^[A-Za-z]+$/i })} />
      <input type="number" {..register("age", { min: 18, max: 99 })} />
      <input type="submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

As you noticed this is just the initialization of validation. We’ll need a way to show the error message to the user.

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

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("firstName", { required: true })} />
      {errors.firstName?.type === 'required' && "First name is required"}

      <input {...register("lastName", { required: true })} />
      {errors.lastName && "Last name is required"}

      <input type="submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

For more resources, related to React-hook-form, feel free to access:


✨ React Final Form

React-Final-Form is a thin wrapper around Final-Form library. It doesn't have any other dependency than the Final Form and the size is really lightweight ~= 3.3kb (minified and gzipped).

You can build forms with React-Final-Form easily using the Form and Field component of React Final Form. I’ll show you how to do that in a few moments.

React Final Form — Open-Source Library.


React-Final-Form Pros

  • Renders only the changed inputs
  • Only 3.2kb (minified and gzipped)
  • 6k+ stars on Github

React-Final-Form Cons

  • Has a peer dependency: Final Form.
  • A lot of boilerplate code
  • 350+ issues on Github

Install React-Final-Form

$ npm install final-form react-final-form
// OR 
$ yarn final-form react-final-form
Enter fullscreen mode Exit fullscreen mode

To build a form you’ll need to import the Form and Field component from react-final-form.


Form Sample Source Code

import { Form, Field } from 'react-final-form'

import React from 'react'
import { render } from 'react-dom'
import Styles from './Styles'
import { Form, Field } from 'react-final-form'

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

const onSubmit = async values => {
  await sleep(300)
  window.alert(JSON.stringify(values, 0, 2))
}

const App = () => (
  <Styles>
    <h1>React Final Form - Simple Example</h1>

    <Form
      onSubmit={onSubmit}
      initialValues={{ firstname: '', lastname :''}}
      render={({ handleSubmit, form, submitting, pristine, values }) => (
        <form onSubmit={handleSubmit}>
          <div>
            <label>First Name</label>
            <Field
              name="firstName"
              component="input"
              type="text"
              placeholder="First Name"
            />
          </div>
          <div>
            <label>Last Name</label>
            <Field
              name="lastName"
              component="input"
              type="text"
              placeholder="Last Name"
            />
          </div>

          <div className="buttons">
            <button type="submit" disabled={submitting || pristine}>
              Submit
            </button>
            <button
              type="button"
              onClick={form.reset}
              disabled={submitting || pristine}
            >
              Reset
            </button>
          </div>
        </form>
      )}
    />
  </Styles>
)

render(<App />, document.getElementById('root')) 
Enter fullscreen mode Exit fullscreen mode

As you can see this form is almost like the Formik form. To build a form the

component takes 3 props: initialValues, handleSubmit and render.

This is a basic form with React Final Form without validation. The validation in React Final Form is provided in two flavors, just like Formik

  • 👉 Form-level validation
  • 👉 Field-level validation

Because the validation code pattern is quite similar to Formik we will skip the samples for now. For more information related to React Final Form, please access:


✨ So, Which one should you choose?

Choosing a form library should be dependent on what type of project you are building. Still, there are a few global points to choosing one library over another.

After all these comparisons If I start any project right now, I’ll choose React-Hook-Form, because it has zero dependencies and less boilerplate code compared to React-Final-Form and Formik.

Formik and React-Final-Form make forms complicated while React-Hook-Form looks cleaner and more intuitive at first look. Also, the validation provided by React-Hook-Form uses less code to finish the job.

At the end of the day, feel free to choose Formik, or React-Final-Form for your project. It’s completely up to your personal preference.


Sorry for this super long article. For those that are still here, the next section presents a few React Products that use production-ready React Forms.


React Berry (uses Formik)

Berry is a creative React Dashboard built using the Material-UI. It is meant to be the best User Experience with highly customizable feature-riched pages. It is a complete game-changer React Dashboard with an easy and intuitive responsive design on retina screens or laptops.

The product comes with a simple JWT authentication flow: login / register / logout powered by an open-source Node JS API Backend via Passport Library.


Berry — Open-Source React Project that uses Formik<br>


React Datta Able — (uses Formik)

Datta Able is an open-source React Dashboard that provides a colorful and modern design. Datta Able React Free is the most stylized React Free Admin Template, around all other admin templates in the market.


Datta Able — Open-Source React Project that uses Formik.

Top comments (31)

Collapse
 
hunghvu profile image
Hung Vu

The choice of validation tool sure depends on your choice of UI library. If I want to bootstrap a project with controlled components as fast as possible, then Formik is a great choice. However, it really does not scale well with complex form.

React Hook Form was born to solve the performance problem, but well, making it maintainable with external controlled components is a nightmare. God forbids me when I use React Hook Form with MUI, on a form that has ~100 fields or more.

It is a trade-off I would say, and apparently, there is no solution in-between that is a jack of all trades.

Collapse
 
brianmcbride profile image
Brian McBride • Edited

I realize it is a pain, but you can just create a higher order component for MUI components to make React Hook Form "just work". But, you only have to do it once. Then you can have a FormTextField to use instead of just the TextField.

A quick search pulled up this open source code: github.com/dohomi/react-hook-form-mui
There migh be better, honestly I just rolled my own when I was using React Hook Form. But this is a solid example.

Collapse
 
sm0ke profile image
Sm0ke

Noted also.
🚀🚀

Collapse
 
techsaq profile image
Mohd Saquib

Can you please provide more details why not to use react hook form with MUI as i am thinking to use these two.

Thanks

Collapse
 
hunghvu profile image
Hung Vu • Edited

It's NOT about avoiding the usage react-hook-form with MUI. It's more about a complexity of integration when your forms become complex (e.g., 50 fields with conditional choices) should be put into consideration.

MUI uses controlled components (e.g., TextField), which means a component has its own internal state (not controlled by the DOM). Indeed, <input> is used underneath and its properties are exposed via inputProps. The great thing about Formik is it can directly work with controlled components. Here is an example of Formik with MUI: formik.org/docs/examples/with-mate....

react-hook-form is more complicated to setup in the long run. react-hook-form by design targets as native and uncontrolled components. It has Controller to help work with external controlled components from libraries like MUI. However, ref of internal input of a component must be exposed somehow, which is not always the case (not a must, see Bill's explaination in the thread below). At that point, you will need to find a hacky way to ensure react-hook-form a single source of truth.

You may ask why don't we break down a form to have smaller chunks. The thing is, some forms have tightly-coupled sections by nature (U.S tax form for example). Breaking it down will result in other set of problems, such as global state control, and can even be more complicated.

Hope this helps!

Thread Thread
 
sm0ke profile image
Sm0ke

Ty Hung for your feedback!
With all collected feedback a new improved version will be published at some point.
🚀🚀

Thread Thread
 
bluebill1049 profile image
Bill • Edited

Hi there,

Thanks for the feedback. React hook form maintainer here :) I would like to address some of the misconceptions and misunderstanding here.

However, ref of internal input of a component must be exposed somehow, which is not always the case.

That's simply not the case, for controlled component react hook form doesn't require users to provide ref, the only reason why we are asking for ref is for focus management. We care a lot about accessibility and especially focus on management. So by providing the input ref, we can focus on that errored input if validation fails. However, it's an optional thing to do, but we highly recommend that.

For those who are interested are what's Controller, You can watch this video: youtube.com/watch?v=N2UNk_UCVyA which I try to explain how the controller is been built.

Form libraries are generally there to solve a part of your form management, it's not going to be a full solution to solve how you structure your application and break down different parts of your forms. You will still have the responsibility to manage your application and structure them in a meaningful and maintainable way.

As we understand integration with other controlled components is always a challenge due to different component API designs, while the form library has to be as generic as possible. This is something we are constantly seeking to improve. The following codesandbox may help some of you out there (it does live in the doc under Controller).

codesandbox.io/s/react-hook-form-v...

Again thanks for your feedback, we (the maintainers) will try our best to make the integration a bit easier in the future.

Cheers
Bill

Thread Thread
 
sm0ke profile image
Sm0ke • Edited

Hello Bill,
Really honored to respond on this thread.
All your feedback is noted for the 2nd version of this article.
Ty for your great work.

🚀🚀

Thread Thread
 
hunghvu profile image
Hung Vu • Edited

Thanks for correct my misunderstanding, Bill! I will adjust my comment to avoid confusion.

react-hook-form is really great when working with native and uncontrolled components thanks to its strength in performance and less verbose code. That said, it is also my preference when working with small, controlled forms too.

At least in my experience, Formik makes huge forms with controlled components maintainable right out of the gate. I have not figured out how to achieve the same experience with react-hook-form though. What I described is more of an edge case, and hopefully react-hook-form can help me handle it efficiently in the future.

Thanks again and keep up the great work 🚀

Thread Thread
 
sm0ke profile image
Sm0ke

Ty for your new remarks Hung Vu.
🚀🚀

Collapse
 
sm0ke profile image
Sm0ke

Ty for reading Saquib!
A new (improved) version of the article will be published in the future.
The new content will cover also your Q.
🚀🚀

Collapse
 
sm0ke profile image
Sm0ke

Ty for your feedback Hung.
Totally agree with you.

Collapse
 
diballesteros profile image
Diego (Relatable Code)

Completely agree with this. Especially switching between two projects. One that uses formik and one that uses react hook form.

The performance problem on Formik in complex forms is extremely annoying and gets into hacky territory when trying to fix it.

Even worse than those is when theres a custom built form library when these alternatives already went through all these problems and at least attempted to fix them.

But oh well as is life.

Collapse
 
hunghvu profile image
Hung Vu

Luckily these two works perfectly well for most of the use cases (e.g., login, profile, product description, etc.). Hopefully there is a library in the future which targets at complex form (like medical report 😩).

Admittedly, building a large form in React is really something due to the way its ecosystem handles global state.

Collapse
 
brianmcbride profile image
Brian McBride • Edited

After a while, I ended up stopping use of any of these libs.

For a while, I was using a lib called Hookstate.js hookstate.js.org/
It is a very clever lib. It has great performance in updating child components. I built a set of higher order components to my UI library. I could just pass into a field a scoped state as documented here: hookstate.js.org/docs/scoped-state. It looked like this in use:

const state = useState({
    email:  '',
    password: '',
});
Enter fullscreen mode Exit fullscreen mode
<StateTextField
    required
    label="Email Address"
    name="email"
    autoComplete="email"
    state={state.email}
/>
Enter fullscreen mode Exit fullscreen mode

This is great. Hookstate will only update the StateTextField on change making huge forms VERY performant. If you ever had to deal with a very large form where an update to one field causes a redraw on all, you'll know what I mean. Unfortunately, PRs and Issues are piling up with Hookstate. Sadly, the maintainers might have less interest in keeping things updated.

I'm currently giving Zustand a go github.com/pmndrs/zustand
It is a very small library, less than 1kb.
The goal is to use it as a form validation lib as well as handle my other global state needs.

I am adding a form wrapper like to Zustand like: github.com/Conduct/zustand-forms is what I am looking to do. If you look at the source in this repo, you'll see that it just isn't that much code.

<TextInput
  value={formValues.password}
  onChange={(v) => updateInput({inputId: 'password', v})}
/>
Enter fullscreen mode Exit fullscreen mode

You could make it more complicated by tracking the ref and id of the component and auto matching that with your data object. That code snipped seems ok though, even with a larger or dynamic form.

Of course, your own wrapper might be like what I did with Hookstate where I pass it in a state reference and use the component's name or id to map to the state's field name.

So, now I have zustand (which has use-sync-external-store as a dep), zustand-forms (which has immer as a dep). I'm at 4 libs. You could probably refactor not to use immer as well. The point is, if you are like me and use some global state tooling (whatever it is), the form libs become just another item to pile on the stack. The whole solution likely being under 2kb. Of which most of that was going to be in my code anyway.

Collapse
 
sm0ke profile image
Sm0ke

Hello Brian & ty for you feedback.
Zustand looks good, I will take a look.

Collapse
 
calag4n profile image
calag4n

I've once used react-hook-form on a pretty big web app project .
At first, I've found it fun but when forms become large, complex and dynamic, we've seen it's limitations, many troubles, bad experience... Then we switched all app to Formik.

And since then, if I need strong and reliable forms I use Formik.
So, my advice is : be careful with react-hook-form !

Collapse
 
uithemes profile image
ui-themes

Thanks for writing!
Size is not a super problem. I'm using Formik and probably stick to it for a while.

Collapse
 
sm0ke profile image
Sm0ke

🚀🚀

Collapse
 
crearesite profile image
WebsiteMarket

React Final Form code looks cleaner.
Thanks for sharing!

Collapse
 
sm0ke profile image
Sm0ke

🚀🚀

Collapse
 
brense profile image
Rense Bakker

Formik also provides hooks if you prefer that pattern

Collapse
 
swaniyah profile image
❄ Saamiyah ☼ • Edited

Which one would you recommend for scalable forms where performance is an important factor.

Collapse
 
sm0ke profile image
Sm0ke

React-Hook-Form ...
Thanks for reading Saamiyah

Collapse
 
sm0ke profile image
Sm0ke

Hello Luke & Ty for your note.
🚀🚀

Collapse
 
bluebill1049 profile image
Bill

Thank you for writing this length and detailed comparison! ❤️

Collapse
 
sm0ke profile image
Sm0ke

Yw Bill!
🚀🚀

Collapse
 
admindashboards profile image
admin-dashboards

wow ...

Collapse
 
sm0ke profile image
Sm0ke

ty!
🚀🚀