Create powerful and flexible forms with React Hook Form. 🪝
Tags: javascript, react, webdev, tutorial
Published: 2021-04-21 14:39:53

Someone inputting his details and hitting that ‘Submit’ button is one of the most widely used and reliable forms of getting the data from a user on any website. We call such web entities ‘forms’ and forms on a webpage are nothing but a collection of elements that allows a user to enter data that is then sent over to the server for further processing.

While the traditional approach to build, code and gather information from a form in a webpage can simply be done with the power of HTML code, but when the website gets complex or scales up in size, (say, when you are on an e-commerce website), we need to leverage some of the external libraries that were meant to get things done easily and are able to integrate with other tech stacks quickly.

One such open-source library to handle all things related to forms is React Form Hook and in this article, we will get to know how to use this with a suitable example.


## About the library

> **[React Form Hook](https://react-hook-form.com)** is a React library that is used to make performant, flexible, and extensible forms with easy-to-use validation support.

Sure, there have been other libraries like [Formik](https://formik.org), [React Final Form](https://final-form.org/react), etc. that falls under similar lines but here’s why it goes above all those:

1. **Small in size**: it’s a tiny library with no other dependencies to install.
2. **Performance**: the best part is that it minimizes the re-renders required and also mounts up fairly quickly, thereby increasing the overall experience.
3. **Uses existing HTML**: you can leverage the powers of HTML to work with this library.
4. **Less code and more features**: almost every form handling scenario is covered all in fairly fewer lines of code.

Now that we have some information, here’s what the rest of the blog will tell you about:

- [Installation](#installation)
- [API references with examples](#api-references)
- [A quick but powerful demo](#a-quick-but-powerful-demo)
- [Conclusion](#conclusion)


## Installation

Time to make our forms powerful with the use of React Hook Forms! Fire up your terminal and then execute the following commands which makes a new React project:

```bash
npx create-react-app react-form-hook-demo 
cd react-form-hook-demo
npm start
```

Your default React project should be running in your browser by now. Next, we need to add the library. Use the following command to install:

```bash
npm install react-hook-form
```


## API References

Before we move ahead typing code carelessly, we need to know how this library works, or more precisely what are the different APIs it has and how they function. Here are some common ones:

1️⃣ **[The `useForm` API](https://react-hook-form.com/api#useForm)**: this is one of those functions which you will be calling first before you apply any handling logic to your existing forms. It takes some optional arguments like `mode`, `defaultValues`, `shouldFocusError`, etc.

```js
const { register } = useForm({
  mode: 'onSubmit',
  reValidateMode: 'onChange',
  defaultValues: {},
  resolver: undefined,
  context: undefined,
  criteriaMode: "firstError",
  shouldFocusError: true,
  shouldUnregister: true,
})
```

As for its methods, take a look at how these are used:

- [`register`](https://react-hook-form.com/api#register): allows you to register an input/select ref and apply validation rules into React Hook Form based on both HTML default and custom validations.

```js
<input name="test" ref={register} />

<input
  name="test"
  ref={
    register({
      required: true
    })
  }
/>
```

- [`unregister`](https://react-hook-form.com/api#unregister): allows you to unregister a single input or an array of inputs.

```js
const {  unregister } = useForm();

<button type="button" onClick={() => unregister("lastName")}>unregister</button>
```

- [`errors`](https://react-hook-form.com/api#errors): it’s an object which contains form errors and error messages corresponding to each field. 

_Note that this will get deprecated in the next major version (i.e. v7). `formState` is likely to be the alternative._

```js
const { errors } = useForm();

<input name="singleErrorInput" ref={register({ required: true })} />
{errors.singleErrorInput && "Your input is required"}
```

- [`handleSubmit`](https://react-hook-form.com/api#handleSubmit): it’s a function that will pass the form data when form validation is successful and can be invoked remotely as well.

```js
const { register, handleSubmit } = useForm();
const onSubmit = (data, e) => console.log(data, e);
const onError = (errors, e) => console.log(errors, e);

<form onSubmit={handleSubmit(onSubmit, onError)}>
      <input name="firstName" ref={register} />
      <input name="lastName" ref={register} />
      <button type="submit">Submit</button>
 </form>
 ```

- [`setError`](https://react-hook-form.com/api#setError): allows you to manually set one or more errors.

```js
const { setError, errors } = useForm();

<input 
  name="username"
  type="text"
  onChange={() => {
      setError("username", {
      type: "manual",
      message: "Dont Forget Your Username Should Be Cool!"
    });
  }}
  ref={register} />
  
  {errors.username && <p>{errors.username.message}</p>}
```

2️⃣ [**The `Controller` API**](https://react-hook-form.com/api#Controller): it’s a wrapper component that makes it easier to work with external components from other libraries and frameworks like [React-Select](https://react-select.com/home), [Material UI](https://material-ui.com), etc.

```js
<Controller
  control={control}
  name="test"
  render={(
    { onChange, onBlur, value, name, ref },
    { invalid, isTouched, isDirty }
  ) => (
    <Checkbox
      onBlur={onBlur}
      onChange={(e) => onChange(e.target.checked)}
      checked={value}
      inputRef={ref}
    />
  )}
/>
```

3️⃣ [**The `useWatch` API**](https://react-hook-form.com/api#useWatch): if you want to reduce the re-rendering at the component level of your form then this API ‘watches’ for any changes to result in better performance.

```js
function IsolateReRender({ control }) {
const firstName = useWatch({ control, name: 'firstName', defaultValue: 'default' });

return <div>{firstName}</div>; 
}

function App() {
  const { register, control, handleSubmit } = useForm();
  
  return (
    <form onSubmit={handleSubmit(data => console.log("data", data))}>
      <input ref={register} name="firstName" />
      <input ref={register} name="last" />
      <IsolateReRender control={control} />
      
      <input type="submit" />
    </form>
  );
}
```

## A Quick but powerful Demo

Okay, now we know most of the APIs and functions to use from this library. Let’s put that into work by creating something fruitful. How about we make the following form?

{% codesandbox react-hook-form-demo-wv3px %}

Here is what’s happening in the form interface:

We have six basic elements in the form; 4 text fields, 1 select field, and lastly a button. We will be adding some important form validations in each of these elements except the select field. Here are all the rules to be implemented:

1. _The First Name_: it should not be empty and should have a minimum length of 5 characters. 

2. _The Last Name_: it is required and has a maximum of 15 characters. 

3. _The Email_: like others, this cannot be left blank.

4. _Username_: this also should not be blank but also we have a custom validation where only the string “John” will be accepted. The error will pop out asynchronously after 3 seconds.

Finally, when you click on the Submit button, an alert is shown along with the entered details. If any validation check goes wrong, the error will be shown instantly and the data won’t submit.

Okay, enough of the information, let’s quickly begin coding all of this..

**1. Code the interface**

Open the _index.js_ file and inside the `return` statement, start by using a `<form>` element. Make sure you don’t add any `action` or `method` attributes. Everything will be handled by the library.

Our first label will be of the “First Name” field. Make sure you add a suitable placeholder value to its `<input>` element. Here we added “John”. The same goes for the “Last Name” field.

Then we have the “Email” field. Here we can specify that the type of the form element is “email” so that it knows beforehand that a proper email syntax should be added. Why not use some good old powers of HTML!

The “Username” field is the same as the name fields. So, it’s important to add a placeholder value here too.

Up next the `select` field is to be added with the `name` attribute along with multiple options you want to provide in the drop-down. Here we need to make sure that each of the <option> elements must have a proper “value” attribute attached to it. It will be used later when we use the library.

After you have coded all the form interface you will have a code similar to this:

```js
<form>
     <h1>Sign Up</h1>

     <label>First Name</label>
     <input
       name="name"
       placeholder="John" />

     <label>Last Name</label>
     <input
       name="name"
       placeholder="Doe"  />

     <label>Email</label>
     <input
       name="email"
       type="email"
       placeholder="john@doe.com" />

     <label>Username</label>
     <input
       name="username"
       placeholder="Only John is accepted" />

     <label>How you got to know about us?</label>
     <select name="info">
       <option value="">Select source...</option>
       <option value="Twitter">Twitter</option>
       <option value="Facebook">Facebook</option>
       <option value="Other">Other</option>
     </select>

     <input type="submit" />
 </form>
```

**2. Power up the form with validation**

With the single `useForm` hook, we will be doing almost all of the operations to make it functional.

Start by importing the hook from the library:

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

Now it’s time to register all the inputs we have used in the HTML code above. For that, we will be calling the imported useForm hook as:

```js
const { register, handleSubmit, errors } = useForm();
```

We have to handle the functioning of the data submission. For that, we will be using the `onSubmit` attribute of the `<form>` element. We call the `handleSubmit` function passing on a new `onSubmit()` method to it. We haven’t added any code to this new method so let’s do that first.

Make this new method after you register the inputs. We will pass on the data obtained from the form. We use JavaScript’s [`alert()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) method inside which we use [string interpolation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) so that we have a dynamic text string shown in the alert box. We can also log down the data into the console just to make sure our object prints out as we are expecting.

```js
const onSubmit = (data) => {
   console.log(data);
   alert(
     `Here are your details: \nName: ${data.name} \nEmail: ${data.email} \nUsername: ${data.username} \nSource: ${data.info}`
   );
 };
```

With the power of [`refs`](https://reactjs.org/docs/refs-and-the-dom.html) in React, we access a particular DOM node in the `render()` method. Hence, for all the 4 inputs and the 1 select element of the form, we add the `ref` attribute which calls the `register` function of the `useHook` API.

Now here comes all the goodies! Everything we need to validate, we can pass inside this `register` function. This makes the form very flexible to change and each element can have similar or dissimilar validations as you like.

For the “First Name” and the “Last Name” fields, we pass on the boolean `true` value to the required property along with a `minLength` of `5` and `max` length of `15` characters.

To apply the error messages to a specific field (say, `name`), simply use the `errors` prop along with the property `name` like `errors.name` or `errors.name.type`. Then we can add any HTML element inside this check like a simple paragraph that says “First Name is required!”.

```js
{errors.name && errors.name.type === "required" && (
    <p>First name is required!</p>
)}
```
As for the message for the minimum length check, we check the `errors.name.type === "minLength"` and pass on the custom message.

```js
{errors.name && errors.name.type === "minLength" && (
       <p>This requires min length of 5!</p>
)}
```
But what about the Username field where we only want specific data to be valid? For this to work as expected, we need to use the validate property of the `register` function. The value of this property can be a separate function where the actual logic of the validation can be stored.

We are using the `sleep()` method so that the error is shown after 3 seconds to the user and this will only fire if the value of the string is not equal to “John”.

```js
const validateUserName = async (value) => {
   await sleep(3000);

   if (value === "John") return true;

   return false;
 };
```

Make sure you predefine the async event code for this to function:

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

Sweet! The form should now be backed by powerful validations and is equally flexible with its elements. Test out your new form and you will see an alert box with all the inputs.

Here’s the entire code along with accessibility attributes we wrote for making this form: 

```js
function App() {
 const { register, handleSubmit, errors } = useForm();

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

 const onSubmit = (data) => {
   console.log(data);
   alert(
     `Here are your details: \nName: ${data.name} \nEmail: ${data.email} \nUsername: ${data.username} \nSource: ${data.info}`
   );
 };

 const validateUserName = async (value) => {
   await sleep(3000);

   if (value === "John") return true;

   return false;
 };

 return (
   <form className="App" onSubmit={handleSubmit(onSubmit)}>
     <h1 aria-level="1">Sign Up</h1>

     <label htmlFor="First name">First Name</label>

     <input
       name="name"
       aria-invalid={errors.name ? "true" : "false"}
       placeholder="John"
       ref={register({ required: true, minLength: 5 })}
     />

     {errors.name && errors.name.type === "required" && (
       <p role="alert">First name is required!</p>
     )}

     {errors.name && errors.name.type === "minLength" && (
       <p role="alert">This requires min length of 5!</p>
     )}

     <label htmlFor="Last name">Last Name</label>
     <input
       name="name"
       placeholder="Doe"
       aria-invalid={errors.name ? "true" : "false"}
       ref={register({ required: true, minLength: 5, max: 15 })}
     />

     {errors.name && errors.name.type === "minLength" && (
       <p role="alert">This requires a min length of 5!</p>
     )}

     <label>Email</label>
     <input
       name="email"
       type="email"
       aria-invalid={errors.email ? "true" : "false"}
       placeholder="john@doe.com"
       ref={register({ required: true })}
     />

     <label>Username</label>

     <input
       name="username"
       aria-invalid={errors.username ? "true" : "false"}
       placeholder="Only John is accepted"
       ref={register({
         required: true,
         validate: validateUserName
       })}
     />

     <label>How you got to know about us?</label>

     <select
       name="info"
       aria-invalid={errors.info ? "true" : "false"}
       ref={register({ required: true })}
     >
       <option value="">Select source...</option>
       <option value="Twitter">Twitter</option>
       <option value="Facebook">Facebook</option>
       <option value="Other">Other</option>
     </select>

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

## Conclusion

This is just the tip of an iceberg when you start making forms with React Hook Form. With its easy-to-go syntax and great features, you can also [use it with TypeScript](https://react-hook-form.com/ts), [create wizard-like multiple forms](https://react-hook-form.com/advanced-usage#WizardFormFunnel) and even [use their online form builder](https://react-hook-form.com/form-builder) where you simply add the elements you want along with rules, and bam! You get your generated code in one click.

---

Hope you liked the information. You can comment below with your thoughts about it.

And now...as always, enjoy a meme! 😆

---

## The [#DevHumour](https://twitter.com/search?q=%23devhumour&src=typed_query) Corner 😂

![Dev Humour Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdr0fsfnxcuurdaq84tj.jpeg)

---

## Some of my previous articles

- [Create smoking Hot toast notifications in React with React Hot Toast. 🔥](https://dev.to/vaibhavkhulbe/create-smoking-hot-toast-notifications-in-react-with-react-hot-toast-30p8)
- [5 really cool web technologies to know! 🤩](https://dev.to/vaibhavkhulbe/5-really-cool-web-technologies-to-know-2maj)
- [5 quick and easy fixes to improve your React app performance 🚀](https://dev.to/vaibhavkhulbe/5-quick-and-easy-fixes-to-improve-your-react-app-performance-5g43)

---

## Find me on

| [Twitter 🐦](https://twitter.com/vaibhav_khulbe)  | [Instagram 📸](https://instagram.com/vaibhavkhulbe143/)   | [LinkedIn 👨🏻‍💻](https://www.linkedin.com/in/vaibhav-khulbe/)  | [Everywhere else 🌐](https://about.me/vaibhav_khulbe)
|---|---|---|---

---

#### [📫 Subscribe to my weekly developer newsletter 📫](https://mailchi.mp/f59beeac6b9b/devupdates)