Taming Forms With react-hook-form
Tags: react
Published: 2020-11-20 15:21:08

---
title: Taming Forms With react-hook-form
published: true
date: 2020-11-19 15:14:00 UTC
tags: react
canonical_url: https://www.thisdot.co/blog/taming-forms-with-react-hook-form
---

# Taming Forms With react-hook-form

After some time of doing repetitive tasks like handling forms in React.js, you will notice that there is a lot of boilerplate code that can be abstracted into reusable [custom hooks](https://reactjs.org/docs/hooks-custom.html). Luckily, there is plenty of existing Open Source solutions. In this case, we will be using [`react-hook-form`](https://react-hook-form.com/).

## What is `react-hook-form`

`react-hook-form` is a performant, flexible, and extensible form handling library built for React. It exports a custom hook that you can call within your Functional Components, and returns both a `register` function that you pass as a `ref` to your `input` components, and a `handleSubmit` function to wrap your submit callback.

By returning a `register` function that will be added to the `input` component, we can leverage the [Uncontrolled Component](https://reactjs.org/docs/uncontrolled-components.html) pattern to make our application faster and more performant, by avoiding unnecessary re-renders.

## What are we going to build?

To get a better understanding of what `react-hook-form` can do, we will build a simple application showing a list of characters and a form to add them to our list.

[![Screen-Recording-2020-10-19-at-1](https://images.ctfassets.net/zojzzdop0fzx/5c3JaKBvzKcu55dchyYsa9/9de1049712ab24c7cb5ff598788d239b/Screen-Recording-2020-10-19-at-1.gif)](https://images.ctfassets.net/zojzzdop0fzx/5c3JaKBvzKcu55dchyYsa9/9de1049712ab24c7cb5ff598788d239b/Screen-Recording-2020-10-19-at-1.gif)

## Application Setup

Before going right into `react-hook-form`, we will need to prepare our application with the basic file structure and functionality. For this, we will create a new react application (you can either use your preferred starter or cloud IDE).

_If you want to skip the application setup, you can go ahead and fork [this CodeSandbox](https://codesandbox.io/s/react-hook-form-tutorial-app-setup-ox258), but I highly recommend you at least read this section to have a better understanding of what the app does._

### 1. Characters List

Let's start by creating a new component where we will display our characters.

**character-list.js**

```
import React from "react";

function CharacterList({ characters }) {
  return (
    <div>
      <h2>Character List</h2>

      {characters.length === 0 ? (
        <p>
          <em>Your character list is empty</em>
        </p>
      ) : (
        <ul>
          {characters.map((character, id) => (
            <li key={id}>
              {character.name} (<strong>{character.species}</strong>)
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

export default CharacterList;
```

If you have a basic understanding of React, you will notice our `CharacterList` component will receive a `characters` prop, which is an array of objects with the properties `name` and `species`. If the array is empty, we will render a placeholder. Elsewhere, we will render the list.

### 2. Add Character Form

The second step is to create a component that will render the form to add a new character to our list.

**character-form.js**

```
import React from "react";

function CharacterForm({ addCharacter }) {
  const onSubmit = (data) => {
    addCharacter(data);
  };

  return (
    <div>
      <h2>Add character</h2>
      <form onSubmit={onSubmit}>
        <div>
          <input name="name" placeholder="Character name" />
        </div>
        <div>
          <select name="species">
            <option value="sorcerer">Sorcerer</option>
            <option value="knight">Knight</option>
            <option value="human">Human</option>
          </select>
        </div>
        <div>
          <button type="submit">Add character</button>
        </div>
      </form>
    </div>
  );
}

export default CharacterForm;
```

By itself, this component won't do anything because we are not doing anything with the collected data, nor validating our fields. This will be the component where we will be working on the next section of this tutorial.

### 3. The App

Now, let's just create the `App` component where we will render `CharacterList` and `CharacterForm`.

**app.js**

```
import React from "react";

import CharacterList from "./character-list";
import CharacterForm from "./character-form";

function App() {
  const [characters, setCharacters] = React.useState([]);

  const addCharacter = (character) => {
    setCharacters((characters) => [...characters, character]);
  };

  return (
    <div>
      <CharacterList characters={characters} />
      <hr />
      <CharacterForm addCharacter={addCharacter} />
    </div>
  );
}

export default App;
```

We will be saving our character list in `characters` by using the [`React.useState`](https://reactjs.org/docs/hooks-state.html) hook, and passing them down to `CharacterList`. Also, we created an `addCharacter` function that will just add a new character at the end of the characters list, and pass it to `CharacterForm` via prop.

## Let's get to it!

Now that we have our application setup, let's see how can we leverage `react-hook-form` to take our forms to the next level.

### Install `react-hook-form`

```
yarn add react-hook-form
```

### Add `react-hook-form` to your `CharacterForm`

Here comes the fun. First, let's import `useForm` from `react-hook-form`, call the hook in our component, destructure `register` and `handleSubmit` methods out of it (don't worry, I will explain what they do just in a while), wrap our `onSubmit` function with `handleSubmit`, and pass `register` as the `ref` for each one of our form controls.

**character-form.js**

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

function CharacterForm({ addCharacter }) {
+ const { register, handleSubmit } = useForm();
+
- const onSubmit = (data) => {
- addCharacter(data);
- };
+ const onSubmit = handleSubmit((data) => {
+ addCharacter(data);
+ });

  return (
    <div>
      <h2>Add character</h2>
      <form onSubmit={onSubmit}>
        <div>
- <input name="name" placeholder="Character name" />
+ <input ref={register} name="name" placeholder="Character name" />
        </div>
        <div>
- <select name="species">
+ <select ref={register} name="species">
            <option value="sorcerer">Sorcerer</option>
            <option value="knight">Knight</option>
            <option value="human">Human</option>
          </select>
        </div>
        <div>
          <button type="submit">Add character</button>
        </div>
      </form>
    </div>
  );
}

export default CharacterForm;
```

#### The `register` method

By attaching the `register` ref to our form controls, we can start tracking some stuff like the field value, its validation status, and even if the field had been touched or not.

**Important:** the `name` prop is **required** when passing the `register` ref, and it should be **unique**. This way, `react-hook-form` will know where to assign the field value. For more information, [check out the `register` documentation](https://react-hook-form.com/api#register).

#### The `handleSubmit` method

This is a function that wraps our submit callback, and passes the actual form values to it. Under the hood, it also calls `preventDefault` on the form event to avoid full page reloads. It can also be an asynchronous function.

For more information, [check out the `handleSubmit` documentation](https://react-hook-form.com/api#handleSubmit).

### Add some validations

At this point, we have a working form that is able to add characters to our list. However, we are not checking if the field is filled, in order to avoid empty submissions.

With `react-hook-form`, it is as simple as calling the `register` function with a configuration object defining the validation rules. For our case, we will make the `name` field required. Also, we can extract `errors` from `useForm` to show the user if the field has errors.

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

function CharacterForm({ addCharacter }) {
- const { register, handleSubmit } = useForm();
+ const { register, handleSubmit, errors } = useForm();

  const onSubmit = handleSubmit((data) => {
    addCharacter(data);
  });

  return (
    <div>
      <h2>Add character</h2>
      <form onSubmit={onSubmit}>
        <div>
- <input ref={register} name="name" placeholder="Character name" />
+ <input
+ ref={register({ required: true })}
+ name="name"
+ placeholder="Character name"
+ />
+ {errors.name && errors.name.type === "required"
+ ? "Name is required"
+ : null}
        </div>
        <div>
          <select ref={register} name="species">
            <option value="sorcerer">Sorcerer</option>
            <option value="knight">Knight</option>
            <option value="human">Human</option>
          </select>
        </div>
        <div>
          <button type="submit">Add character</button>
        </div>
      </form>
    </div>
  );
}

export default CharacterForm;
```

### Reset the form status

The final step is to clear our form after successfully adding a character to our character list. For that, we will destructure a new method from the `useForm` hook: `reset`, and call it after `addCharacter`.

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

function CharacterForm({ addCharacter }) {
- const { register, handleSubmit, errors } = useForm();
+ const { register, handleSubmit, errors, reset } = useForm();

  const onSubmit = handleSubmit((data) => {
    addCharacter(data);
+ reset();
  });

  console.log(errors.nameRequired);

  return (
    <div>
      <h2>Add character</h2>
      <form onSubmit={onSubmit}>
        <div>
          <input
            ref={register({ required: true })}
            name="name"
            placeholder="Character name"
          />
          {errors.name && errors.name.type === "required"
            ? "Name is required"
            : null}
        </div>
        <div>
          <select ref={register} name="species">
            <option value="sorcerer">Sorcerer</option>
            <option value="knight">Knight</option>
            <option value="human">Human</option>
          </select>
        </div>
        <div>
          <button type="submit">Add character</button>
        </div>
      </form>
    </div>
  );
}

export default CharacterForm;
```

For more information, [check out the `reset` documentation](https://react-hook-form.com/api#reset).

## Moving forward

Now that you have a better sense of how to manage your React forms, you have unlocked a new world of possibilities by using battle-tested and community-validated libraries like `react-hook-form`.

You can take a look at more [advanced use cases](https://react-hook-form.com/advanced-usage), [additional resources](https://react-hook-form.com/resources) or even [take a look at the full API](https://react-hook-form.com/api).

If you want a finished code sample, you can check out [this CodeSandbox](https://codesandbox.io/s/react-hook-form-tutorial-final-code-x3oqr).

_This Dot Labs is a modern web consultancy focused on helping companies realize their digital transformation efforts. For expert architectural guidance, training, or consulting in React, Angular, Vue, Web Components, GraphQL, Node, Bazel, or Polymer, visit [thisdotlabs.com](https://www.thisdotlabs.com)._

_This Dot Media is focused on creating an inclusive and educational web for all. We keep you up to date with advancements in the modern web through events, podcasts, and free content. To learn, visit [thisdot.co](https://www.thisdot.co)._