Creating React TypeScript Forms with react hook form

Creating React TypeScript Forms with React Hook Form is an introductory guide for developers looking to create forms quickly and efficiently using React and TypeScript. This tutorial will provide a step-by-step guide to creating forms: from setting up the project to adding form input fields and handling submitting data. With this tutorial you will be able to create React TypeScript forms with ease, even if this is your first time doing this and don’t have experience using react hooks.

Project Setup And Form Library Installation

Creating React TypeScript Forms will happen sooner or later as you start any new react app. You will need a form, even if it’s just a react typescript login form. So one question might be what types of forms can I create in React Typescript?, or better yet what is the best practice and what would be the most efficient strategy to use? should it be a form component? your own react hooks? it all depends on your use case but I have found that even for simple projects, creating a custom boilerplate form you can understand, extend and reuse would be best option as you code many projects that use React Typescript forms.

Copying & pasting other third party boilerplate code or even code from the docs of code libraries is a great start, but you almost always have to make changes and probably break the code (good for learning, bad if you are short in time), or to find out it had validation rules you don’t need. To start let’s ensure that we can use create-react-app.

On your terminal type the following to ensure you have node installed:

$ node -v
v18.13.0

You should get the version currently installed on your computer. If you don’t see this then you need to install NodeJS with at least the latest LTS version.

For windows:
I recommend installing Cmder as a terminal application. Then run the following command to install the latest LTS version:

$ nvm install --lts

For Mac and Linux:

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash

Then run:

$ nvm install --lts

Why Use TypeScript?

With NodeJS installed we are ready to get started with create-react-app, but before that, are you new to TypeScript? or react TypeScript types? If you are, then the main thing to know about it is that it is a typed superset of JavaScript that compiles to plain JavaScript. So all you write in TypeScript gets translated back to JavaScript.

How does that help me? you may ask. And I did ask that same question before I starting using it. As you start to code you will start to see and appreciate protection it offers your code when you can quantify the many simple type errors we make on a type-free language like JavaScript. You can avoid them writing your code with TypeScript. It keeps your code with less errors, it is purpose-driven and with much less ambiguity.

I will be writing another blog post with many examples of how TypeScript helps, but for the remainder of this post you can consider TypeScript important for any small or big projects. Some people argue about the verbosity TypeScript types, but I prefer my code a bit more verbose than repeatedly introducing the same bugs all the time.

Create React App Project Setup with React TypeScript Forms

The first step to get started is to go to our home folder where our our project files will be stored, so let’s go to our home folder (~):

$ cd ~

Next, let’s run create react app project with TypeScript. We’ll be using npx which tells our package manager to run it (create-react-app) without installing it.

$ npx create-react-app --template typescript my-react-form

This will create the my-react-form folder for you and start with all the basic files to get started, as that is what create-react-app does for us. We’ll also install react hook form later. Building forms and being able to scale them as the requirements evolve can be challenging, that is the main reason we are using react hook form.

Now let’s get inside that folder:

$ cd my-react-form

Exploring package.json

One of the most important files here is the package.json file that keeps track of all the dependencies or other code libraries we are using in our current project. If we look under “dependencies” we will see a list of all the packages or library code that will be shipped when we package this project. Of special interest you will see ones named @types/*** . These packages contain type definitions for libraries originally written in JavaScript – which helps specially when the author of such code libraries have not yet transitioned to TypeScript. These TypeScript types are maintained separately on the DefinitelyTyped GitHub repo.

Also note that the version of both packages (the package and @type/* for that package) don’t need to match exactly and they work as expected. We will be adding react hook form soon.

Coding the React TypeScript Form

If you open the src folder with your favorite IDE, we can find the files we are going to work with. The extension .ts and .tsx are the typescript files. These are TypeScript files with JSX code (similar to HTML) .tsx, and plain TypeScript files (.ts)

For now let’s open the file App.tsx as it is our entry point to create this app. On a real project you would create a file like MyForm.tsx instead of creating this form directly here, but for the purposes of this tutorial we’ll create it here. The file should have:

import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

Let’s first remove everything between the outer div to this:

import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
    </div>
  );
}

Great, now let’s install our form library. The form package we are going to use is react hook form. But before that we need to install it. On the terminal while inside our root project folder type:

$ npm install react-hook-form --save

This will install the all powerful react hook form library which will help us for the remainder of this tutorial.

First lets import the form library at the top of our file:

import React from "react";
import { SubmitHandler, useForm } from "react-hook-form"; // <- import this

Then a type for our subscription enum field for yes/no, and a type for our form (under all imports):

// imports are above this line

enum SubscriptionEnum {
  yes = "yes",
  no = "no",
}

type IFormInput = {
  firstName: string;
  lastName: string;
  email: string;
  subscribe: SubscriptionEnum;
};

What we are declaring here are the TypeScript types for each field so we can have predictable results when accessing the form data. For the first, last and email input fields we specified as string fields. Next we have the subscribe field which is of type SubscriptionEnum that can only have a yes/no value. TypeScript Enums restrict the literal values the input can receive.

Now lets put this form together using the register() function provided by react hook form and the form input fields:

  return (
    <div className="App">
      <form onSubmit={handleSubmit(onFormSubmit)}>
        <label>First Name</label>
        <input {...register("firstName")} />
        <label>Last Name</label>
        <input {...register("lastName")} />
        <label>Email</label>
        <input {...register("email")} />
        <select {...register("subscribe")}>
          <option value="yes">Yes</option>
          <option value="no">No</option>
        </select>
        <input type="submit" />
      </form>
    </div>
  );

Notice the register() functions. These functions will return the necessary props from react hook form for it to work correctly. The reason you see the three dots (…) in-front is to expand this expression and assign these props (short for ‘properties’) to each of the form elements using the spread syntax. If you are confused, just think of this as a way to expand all object properties and place them on each of the form elements.

React Hook Form with TypeScript using React hooks

What we have left is connecting the event handler of the form that will trigger when we click on the submit button. For this we are going to need another function provided by react hook form called handleSubmit. This form library gives us so many features with it’s react hooks, that there is a lot to learn.

Let’s first get the register and handleSubmit functions from the react hook form provided function called useForm. This should go at the top of the App() function:

const { register, handleSubmit } = useForm();

You’ll notice that we are using a deconstructing assignment to pull the register and handleSubmit functions because useForm returns an object. Next we’ll use it as a type parameter that tells TypeScript the type of form data that our form will be handling: a firstName, lastName, email and subscription fields with their respective TypeScript types we declared above. This is what is called TypeScript Generics, which we will explaining more in detail later. For now to understand it: it interprets it like a list of the fields our form will be supporting, and will warn us in case we add more fields not already declared on our IFormInput type.

As a final step we will be creating our actual form submit handler that will get triggered when we click the submit button. This will give us access to all the form data and trigger any custom action code we need. This submit handler function will only be called if the form validation rules passed successfully (no errors were found). On this tutorial we don’t add form validation rules, but we’ll be doing that on a future post. Your code should look like the following:

const onFormSubmit: SubmitHandler<IFormInput> = (data) => { console.log(data); };

We have the name of our variable onFormSubmit of form type SubmitHandler and that SubmitHandler we are telling it the type of data that it should be getting using TypeScript generics (via our IFormInput type declaration). This allows TypeScript to know the data we are working with inside our submit handler and auto-complete works when you add a dot (.) after the data parameter to reveal the form fields! Awesome!

With this our code now looks like the following:

import React from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import "./App.css";

enum SubscriptionEnum {
  yes = "yes",
  no = "no",
}

type IFormInput = {
  firstName: string;
  lastName: string;
  email: string;
  subscribe: SubscriptionEnum;
};

function App() {
  const { register, handleSubmit } = useForm<IFormInput>();

  const onFormSubmit: SubmitHandler<IFormInput> = (data) => {
    console.log(data);
  };

  return (
    <div className="App">
      <form onSubmit={handleSubmit(onFormSubmit)}>
        <label>First Name</label>
        <input {...register("firstName")} />
        <label>Last Name</label>
        <input {...register("lastName")} />
        <label>Email</label>
        <input {...register("email")} />
        <select {...register("subscribe")}>
          <option value="yes">Yes</option>
          <option value="no">No</option>
        </select>
        <input type="submit" />
      </form>
    </div>
  );
}

export default App;

Let’s run our app on your terminal by typing:

$ npm start

Open your browser console Opt + Cmd + I or Alt + Win + I keys on Windows.

Type your info on the form when click the submit button. Finally take a look at the console and see all the data you typed there!

We did it! we were able to create a simple form using TypeScript and the popular react hook form package that is really handy to use on any React project. Some may say: “but can’t I create a form without react hook form?” And the answer is: yes, you can. But I find it really convenient to use this library as it offers so many great features like form validation, error handling, fast re-renders, TypeScript Generics friendly and much more. It is a very robust form library that you would be using again and again on many projects.

Conclusion

On this tutorial we started a new create react app project, installed react hook form and then used its react hooks to connect our form input fields, then associated the necessary TypeScript Types to the form while we did this. At the end we connected our form with a form submit handler in a way that TypeScript knew exactly all the form fields we were working with.

This is just the tip of the iceberg of course. We’ll continue expanding our form to have useful validation rules that will trigger react form validation when the user makes a mistake (using a validation library versus our own form validation), the use of react hooks, sending the form data to the server, customize the look & feel of form elements, creating our own react hooks, and expand on the react hook form TypeScript integration.

Hope this tutorial was helpful to you. If you have suggestions or anything you would like to see in a future post please share it on the comments below. Thanks and be sure to create something amazing today!

About The Author

Leave a Comment

Your email address will not be published. Required fields are marked *