Carl Rippon

Building SPAs

Carl Rippon
BlogBooks / CoursesAbout
This site uses cookies. Click here to find out more

Getting started with React Hook Form with TypeScript

May 05, 2020
typescriptreact

This is the first in a series of posts on React Hook Form, which, as the name suggests, is a helpful library for building forms in React.

In this post, we are going to build a form to capture a name, an email address, and a score. The form will have some simple validation rules and output its data to the console when submitted.

Installing

React Hook Form’s package name is react-hook-form, so we can install it into our project using the following command:

npm install react-hook-form

The package includes TypeScript types, so there is no additional installation required for this.

Basic form

Let’s start by defining the type for the forms data:

type PersonScore = {
  name: string;
  email: string;
  score: number;
};

So, we want to capture a name, an email address, and a score in our form.

Let’s create our basic form JSX:

export const PersonScoreForm = () => {
  return (
    <form>
      <div className="field">
        <label htmlFor="name">Name</label>
        <input
          type="text"
          id="name"
          name="name"
        />
      </div>
      <div className="field">
        <label htmlFor="email">Email</label>
        <input
          type="email"
          id="email"
          name="email"
        />
      </div>
      <div className="field">
        <label htmlFor="score">Score</label>
        <input
          type="number"
          id="score"
          name="score"
        />
      </div>
      <button type="submit">Save</button>
    </form>
  );
};

No sign of React Hook Form yet - just a basic form. So, let’s start to make use of React Hook Form by registering the fields:

import { useForm } from "react-hook-form";
export const PersonScoreForm = () => {
  const { register } = useForm<PersonScore>();  return (
    <form>
      <div className="field">
        ...
        <input
          ...
          ref={register}        />
      </div>
      <div className="field">
        ...
        <input
          ...
          ref={register}        />
      </div>
      <div className="field">
        ...
        <input
          ...
          ref={register}        />
      </div>
      ...
    </form>
  );
};

We’ve used the register function from useForm hook to register the reference of each field with React Hook Form.

Notice that we’ve passed our form data type, PersonScore, to useForm in its generic parameter. This will ensure our form is strongly-typed.

Form submission

Let’s create a submission handler for the form:

export const PersonScoreForm = () => {
  const { register, handleSubmit } = useForm<PersonScore>();  const onSubmit = (data: PersonScore) => {    console.log("data", data);  };
  return (
    <form onSubmit={handleSubmit(onSubmit)}>      ...
    </form>
  );
};

React Hook Form provides a submit handler, handleSubmit, which we wire up to our form. We pass a callback function, onSubmit, into handleSubmit, which is called with the field values after React Hook Form has validated them all. If validation fails, onSubmit won’t be called.

When we press Enter or click the Save button, our onSubmit function is called, and the field values are output to the console:

Submit

Basic validation

Let’s turn all the fields in the form to required fields:

<form ... >
    <div className="field">
    ...
    <input
        ...
        ref={register({required: true})}    />
    </div>
    <div className="field">
    ...
    <input
        ...
        ref={register({required: true})}    />
    </div>
    <div className="field">
    ...
    <input
        ...
        ref={register({required: true})}    />
    </div>
    ...
</form>

Validation is specified in the register functions parameter. React Hook Form has a few inbuilt validation rules, and one of those is required validation, which we specify by setting required to true in the parameter object.

If we click the Save button without filling in the form, our onSubmit function will no longer be called, and the focus will be set to the Name field.

Let’s improve the user experience by adding some validation error messages:

export const PersonScoreForm = () => {
  const { register, handleSubmit, errors } = useForm<PersonScore>();  ...
  return (
    <form ... >
      <div className="field">
        <label htmlFor="email">Name</label>
        <input ... />
        {errors.name && errors.name.type === "required" && (          <div className="error">Your must enter your name.</div>        )}      </div>
      <div className="field">
        <label htmlFor="email">Email</label>
        <input ... />
        {errors.email && errors.email.type === "required" && (          <div className="error">Your must enter your email address.</div>        )}      </div>
      <div className="field">
        <label htmlFor="score">Score</label>
        <input ... />
        {errors.score && errors.score.type === "required" && (          <div className="error">Your must enter your score.</div>        )}      </div>
      ...
    </form>
  );
};

We are using the errors object from the useForm hook to render the error for each field if an error exists.

Notice how we check for the rule the error belongs to using the errors.fieldName.type property. We don’t really need to do this in our simple example because there is only one validation rule per field, but this is a useful pattern to use for more complex forms.

Notice how we get intellisense as we navigate through the errors property because our form is strongly-typed. Nice!

errors intellisense

If we click the Save button without filling in the form, the validation errors are now displayed:

Validation errors

A working example of this form is available in CodeSandbox

Wrap up

React Hook Form is super easy and super flexible to work with. We have only scratched the surface in this post.

In the next post, we’ll dive into how you can implement more complex validation rules.

Did you find this post useful?

Let me know by sharing it on Twitter.
Click here to share this post on Twitter

If you to learn more about using TypeScript with React, you may find my course useful:

Using TypeScript with React

Find out more