Building an Advanced Multistep Form with React-Hook-Form
Tags: react, tutorial, frontend, form
Published: 2023-04-25 14:46:04

# Building an Advanced Multistep Form with React Hook Form

In this blog post, we'll demonstrate how to create an advanced multistep form using React Hook Form, a popular form library for React. React Hook Form aims to minimize re-rendering and provides a better developer experience by leveraging hooks and the native HTML form behavior.


## Creating the Form Context

To manage our form data, we'll create a custom form context. This context will store the form data and provide a function to update it.

```jsx
// src/FormContext.js
import { createContext, useContext, useState } from "react";

const FormContext = createContext();

export const useFormContext = () => {
  return useContext(FormContext);
};

export const FormProvider = ({ children }) => {
  const [formData, setFormData] = useState({});

  const updateFormData = (updatedData) => {
    setFormData((prevData) => ({ ...prevData, ...updatedData }));
  };

  return (
    <FormContext.Provider value={{ formData, updateFormData }}>
      {children}
    </FormContext.Provider>
  );
};
```

## Creating the Form Steps

Now, let's create three form steps: Personal Info, Employment, and Review.

### Personal Info Step

```jsx
// src/steps/PersonalInfo.js
import { useForm } from "react-hook-form";
import { useHistory } from "react-router-dom";
import { useFormContext } from "../FormContext";

export const PersonalInfo = () => {
  const { register, handleSubmit } = useForm();
  const { updateFormData } = useFormContext();
  const history = useHistory();

  const onSubmit = (data) => {
    updateFormData(data);
    history.push("/employment");
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="name">Name</label>
        <input {...register("name")} id="name" required />
      </div>
      <div>
        <label htmlFor="email">Email</label>
        <input {...register("email")} id="email" required />
      </div>
      <button type="submit">Next</button>
    </form>
  );
};
```

### Employment Step

```jsx
// src/steps/Employment.js
import { useForm } from "react-hook-form";
import { useHistory } from "react-router-dom";
import { useFormContext } from "../FormContext";

export const Employment = () => {
  const { register, handleSubmit } = useForm();
  const { updateFormData } = useFormContext();
  const history = useHistory();

  const onSubmit = (data) => {
    updateFormData(data);
    history.push("/review");
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="company">Company</label>
        <input {...register("company")} id="company" />
      </div>
      <div>
        <label htmlFor="position">Position</label>
        <input {...register("position")} id="position" />
      </div>
      <button type="submit">Next</button>
    </form>
  );
};
```

### Review Step

```jsx
// src/steps/Review.js
import { useFormContext } from "../FormContext";

export const Review = () => {
  const { formData } = useFormContext();

  return (
    <div>
      <h2>Review</h2>
      <pre>{JSON.stringify(formData, null, 2)}</pre>
      <p>Once you're satisfied with the data, you can submit the form to a backend service or save it to a local storage.</p>
    </div>
  );
};
```

## Setting Up Routes

Now, let's create a `Router` component to handle navigation between the steps:

```jsx
// src/Router.js
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { PersonalInfo } from "./steps/PersonalInfo";
import { Employment } from "./steps/Employment";
import { Review } from "./steps/Review";

export const Router = () => {
  return (
    <BrowserRouter>
      <Switch>
        <Route exact path="/" component={PersonalInfo} />
        <Route path="/employment" component={Employment} />
        <Route path="/review" component={Review} />
      </Switch>
    </BrowserRouter>
  );
};
```

## Updating App.js

Finally, wrap the `Router` component in `App.js` with the `FormProvider`:

```jsx
// src/App.js
import { FormProvider } from "./FormContext";
import { Router } from "./Router";

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

export default App;
```


## Conclusion

In this blog post, we've built an advanced multistep form using React Hook Form and React Router. We've also created a custom form context to manage form data throughout the steps. By following this approach, you can create complex multistep forms with ease, while leveraging the benefits of React Hook Form.

---

As a potential enhancement, you could integrate with third-party libraries like Tutim for schema-based implementation including validation, form persistence, conditional rendering, save draft, and more.