Creating a Form with React Hook Form
Tags: reacthookform, formvalidations, styledcomponents
Published: 2021-05-13 20:24:33

In this tutorial we will build a form with React Hook Form allowing users to create an account. We will also be styling our form with Styled Components. 
___

### Overview
[React Hook Form](https://react-hook-form.com/) is a library for creating forms utilizing concepts from React and HTML. Key features and benefits of React Hook Form includes:
* Hooks for reusable state logic
* HTML client-side validations
* minimal rendering(uncontrolled form)

Below are the [APIs](https://react-hook-form.com/api) we will be using:
* **useForm:** hook with access to different methods from library
* **register:** method to register inputs and apply validation rules
* **handleSubmit**: function that will pass data after validation  
* **errors**: object containing error message corresponding to input field
* **reset**: method to reset all fields on form 

[Styled Components](https://styled-components.com/) is a library for styling UI components. It utilizes template literals for declaring styling directly to a component. Key features and benefits of Styled Components includes:
* ease of maintenance with styling bound to component  
* dynamic styling using props or global themes
* compatible with HTML and CSS naming standards 

Below are the [APIs](https://styled-components.com/docs/api) we will be using:
* **styled:** default export for using library
* **TaggedTemplateLiteral:** CSS properties and values passed into styled calls
* **createGlobalStyle:** function that generates a global styling component
   
Here are links to the [repo](https://github.com/simonxcode/hook-form) and [live site](https://hook-form.netlify.app/) to get a better idea on what will be built. 
___

### Setting Up Project
> My IDE setup and package manager for this project was VSCode and Yarn. If you are using a different setup your commands will be slightly different. 

> This project was built with React Hook Form *6.13.0* and Styled Components *5.2.1*. Keep this in mind as syntax may be different from other versions. 

The quickest way to get started is with [Create React App](https://github.com/facebook/create-react-app). This will allow us to work on the project right away without having to install preliminary dependencies and make configurations. On the command line in VSCode navigate to the directory where you would like to have the project stored. Type `yarn create react-app "project name"` to initialize the project.    
![Command Line](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wyp7bmefva3ps2sngsjy.png)

**Setting Up Component**

We are going to make some minor changes to our files and create a function component that will render a basic form. Below are key highlights along with code snippet and DOM output:  

Key Highlights:
* rename **App.js** file to **Form.js** file
* rename **App** component to **Form** and have it return a basic form containing
 * title, username, email, password and submit button 
* rename **App** component to **Form** component in **index.js** 

Code Snippet:
```javascript
//Form.js
import React from 'react'

function Form() {
  return (
    <div>
      <h1>Almost There!</h1>
      <form>
        <div>
          <input type="text" name="username" placeholder="username" />
        </div>
        <div>
          <input type="text" name="email" placeholder="email" />
        </div>
        <div>
          <input type="password" name="password" placeholder="password" />
        </div>
        <div>
          <input type="submit" value="Create Account" />
        </div>
      </form>
    </div>
  );
}

export default Form;
```

```javascript
//index.js
...
import Form from './Form';

ReactDOM.render(
  <Form />,
  document.getElementById('root')
);
```
DOM Output:
![Basic Form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3duzu0mw2xrsj5nqk4c8.png)
___

### Using React Hook Form
To get started with React Hook Form we will install the library with `yarn add react-hook-form`. We then import `useForm` Hook into **Form.js**. Now we can start integrating some of the features from this library into our project. Below are key highlights along with code snippet: 

Key Highlights:
* import and use `register`, `handleSubmit`, `errors` and `reset` methods
* assign register for each input field to track changes to inputs 
* setup validation rules and error handling within input fields
* declare `onSubmit` event listener that will log data to console
* reset all data after form is submitted

Code Snippet:
```javascript
//Form.js
import React from 'react'
import { useForm } from "react-hook-form";

function Form() {
  const { register, handleSubmit, errors, reset } = useForm();

  const onSubmit = (data) => {
    reset();
    console.log(data);
  };

  return (
   <div>
      <h1>Almost There!</h1>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <input
            type="text"
            name="username"
            placeholder="username"
            ref={register({
              required: "username required",
              pattern: {
                value: /^[a-z][a-z0-9]{3,14}$/i,
                message: "Username must be 5 - 15 characters long, must start with a letter, only alphanumeric characters allowed, only lowercase letters allowed"
              }
            })}
          />
          {errors.username && (<p><em>{errors.username.message}</em></p>)}
        </div>
        <div>
          <input
            type="text"
            name="email"
            placeholder="email"
            ref={register({
              required: "email required",
              pattern: {
                value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{1,64}$/i,
                message: "Please enter a valid email"
              }
            })}
          />
          {errors.email && (<p><em>{errors.email.message}</em></p>
          )}
        </div>
        <div>
          <input
            type="password"
            name="password"
            placeholder="password"
            ref={register({
              required: "password required",
              pattern: {
                value: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,15}$/i,
                message: "Password must be 8 - 15 characters long, must contain one UPPERCASE letter, must contain one lowercase letter, must contain one number, must contain one special character: @$! % * ? &"
              }
            })}
          />
          {errors.password && (<p><em>{errors.password.message}</em></p>
          )}
        </div>
        <div>
          <input type="submit" value="Create Account" />
        </div>
      </form>
    </div>
  );
}

export default Form;
```

**Testing the Form**
Now we will test the form to make sure the following functionalities are working properly: 
* error handling for empty fields
* error handling for invalid fields
* data logging after validation   
* reset of all fields after validation

Dom Output:
* error handling for empty fields
![Empty Field Error Message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/okq2mcw6lftnj2094rsl.png)

* error handling for invalid fields
![Invalid Field Error Message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1hg9swkgxpwk3sqw0fn.png)

* data logging to Console  
![Data Logging to Console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfg6r9fazsjcn7qnnpxc.png)

* reset of all fields after validation
![Form Reset](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a7u56jubrl2dhc6n8ctr.png)
___

### Using Styled Component
To get started with Styled Component we will install the Styled Component library with `yarn add styled-components`. We then import `styled` method into **Form.js**. As noted in the [documentation](https://styled-components.com/docs/basics#installation), if using Yarn, it is recommended to include a resolution field in **package.json**. This will help prevent issues that may result from having multiple versions installed.  
```javascript
//package.json
...
"resolution": {
   "styled-components": "^5"
 }
...
``` 

Below are key highlights along with code snippet and DOM output for styling the **Title** of the form. The same work flow can be applied to all other elements. 

Key Highlights:
* declare a **Title** container and assign it to the styled method
* attach **h1** to styled method to define the element type
* define the CSS properties values within template literal 
* In the return statement replace h1 tag with **Title**
   
Code Snippet:
```javascript
//Form.js
import styled from "styled-components";

const Title = styled.h1`
  color: #00805b;
  font-size: 3rem;
  letter-spacing: 0.0625rem;
  margin-bottom: 0rem;
`;

... 
<Title>Almost There!</Title>
...
```

DOM Output:
![Styled Title](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iamrmhpccpiiwjgpbpjv.png)
___

### Styling Font
> This step is optional and is not required if you are planing to use default [Web Safe Fonts](https://www.w3schools.com/cssref/css_websafe_fonts.asp). 

Styling the fonts for this project was a little tricky because I wanted to use the *Roboto* from [Google Fonts](https://fonts.google.com/). From Styled Component's [documentation](https://styled-components.com/docs/faqs#note-regarding-css-import-and-createglobalstyle) it was not recommended to use `@import` CSS Rule with version(5.2.1). The work around was to install [React Helmet](https://github.com/nfl/react-helmet) in order to reference the url to in a Link tag. 
Here are key highlights along with code snippet and DOM output:
 
Key Highlights:
* install React Helmet library and import into **Form.js**
* reference Google Font urls in Link tags
* import createGlobalStyle method from Styled Component library
* declare `GlobalStyle` container with font family property and values
* import self-enclosed `GlobalStyle` element into **Form** return statement 
* make changes to font weight in the **Title** container

Code Snippet:
```javascript
import { Helmet } from "react-helmet";
import styled, { createGlobalStyle } from "styled-components";

const GlobalStyle = createGlobalStyle`
  body {
    font-family: 'Roboto', sans-serif;
  };
`;

const Title = styled.h1`
  color: #00805b;
  font-size: 3rem;
  font-weight: 500
  letter-spacing: 0.0625rem;
  margin-bottom: 0rem;
`;

...
return (
    <div>
      <GlobalStyle />
      <Helmet>
        <link rel="preconnect" href="https://fonts.gstatic.com" />
        <link
          href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;500&display=swap"
          rel="stylesheet"
        />
      </Helmet>
      <Title>Almost There!</Title>
...

```

DOM Output:
![Styled With Google Font](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xe1xy1ozpr3d9vn59uib.png)
___

### Final Touches
To make sure that our form renders consistently across multiple browsers we will use [Normalize.CSS](https://github.com/necolas/normalize.css/). This library will preserve user defaults styling and help maintain cross browser consistency. Install the library with `yarn add Normalize.CSS` and import it into **Form.js.** 

```javascript
//Form.js
import 'normalize.css';
```

**Final Testing** 
Now that our form application is complete we are going to perform the same test from **Testing the Form**. The purpose of performing the test again is to verify that layout and UI components are functioning and rendering correctly after styling. Here was the list of requirements for testing:
* error handling for empty fields
* error handling for invalid fields
* data logging after validation   
* reset of all fields after validation 

Dom Output:
* error handling for empty fields
![Empty Field Error Message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/koc209wdtlmqtuirmv73.png)

* error handling for invalid fields
![Invalid Field Error Message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/olgztq1296y1pjv79u76.png)

* data logging to Console   
![Data Logging to Console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2itcg7k864f4wxwbkuwr.png)

* reset of all fields after validation
![Form Reset](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fkbcr3940msm2gndmc96.png)
___

### Next Steps:
Forms are the most common and effective tools for collecting data from users. This form can be integrated into any website or full stack application. For best practice in development lifecycle, I am planning to write either an integration or unit test for this project. Stay Tuned! 🙌