Complete Guide: Building a Multi-Step Form in React with react-hook-form

ยท

4 min read

Complete Guide: Building a Multi-Step Form in React with react-hook-form

In this tutorial, we will guide you through the process of creating a multi-step form using the react-hook-form library. Multi-step forms are a fantastic way to break down complex forms into smaller, more manageable sections. By the end of this tutorial, you'll have a solid understanding of how to create an interactive multi-step form in a React application.

Building the Multi-Step Form Component

Create a new file named MultiStepForm.js inside the src directory of your project. This file will contain the main logic for our multi-step form.

import React, { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import StepOne from './StepOne';
import StepTwo from './StepTwo';
import StepThree from './StepThree';

const MultiStepForm = () => {
  const methods = useForm();
  const [currentStep, setCurrentStep] = useState(1);

  const onNext = () => {
    setCurrentStep(currentStep => currentStep + 1);
  };

  const onPrevious = () => {
    setCurrentStep(currentStep => currentStep - 1);
  };

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

  return (
    <div className='min-h-screen bg-gray-800 flex flex-col justify-center items-center py-10'>
      <div className='min-w-[500px] mx-auto bg-white p-8 rounded-lg shadow-lg'>
        <h1 className='text-4xl font-bold mb-4 text-center'>Multi-Step Form</h1>
        <FormProvider {...methods}>
          <form onSubmit={methods.handleSubmit(onSubmit)}>
            {currentStep === 1 && <StepOne />}
            {currentStep === 2 && <StepTwo />}
            {currentStep === 3 && <StepThree />}

            <div className='flex justify-between mt-6'>
              {currentStep > 1 && (
                <button
                  type='button'
                  onClick={onPrevious}
                  className='px-4 py-2 bg-gray-200 text-gray-600 rounded'
                >
                  Previous
                </button>
              )}
              <div className='ml-auto'>
                {currentStep < 3 && (
                  <button
                    type='button'
                    onClick={onNext}
                    className='px-4 py-2 bg-gray-800 text-white rounded'
                  >
                    Next
                  </button>
                )}
                {currentStep === 3 && (
                  <button
                    type='submit'
                    className='px-4 py-2 bg-green-700 hover:bg-green-900 text-white rounded'
                  >
                    Submit
                  </button>
                )}
              </div>
            </div>
          </form>
        </FormProvider>
      </div>
    </div>
  );
};

export default MultiStepForm;

Creating the Form Steps

Now, let's create the individual steps of our multi-step form. We'll create separate components for each step to keep our code organized and modular.

StepOne.js

Create a new file named StepOne.js inside the src directory. This component will handle the first step of the form:

import React from 'react';
import { useFormContext } from 'react-hook-form';

const StepOne = () => {
  const { register } = useFormContext();

  return (
    <>
      <h2 className='text-lg font-medium mb-4'>Step 1: Personal Information</h2>
      <div className='mb-4'>
        <label htmlFor='firstName' className='block text-sm font-medium mb-1'>
          First Name
        </label>
        <input
          type='text'
          id='firstName'
          {...register('firstName')}
          className='w-full p-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        />
      </div>
      <div className='mb-4'>
        <label htmlFor='lastName' className='block text-sm font-medium mb-1'>
          Last Name
        </label>
        <input
          type='text'
          id='lastName'
          {...register('lastName')}
          className='w-full p-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        />
      </div>
      <div className='mb-4'>
        <label htmlFor='email' className='block text-sm font-medium mb-1'>
          Email
        </label>
        <input
          type='email'
          id='email'
          {...register('email')}
          className='w-full p-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        />
      </div>
      <div>
        <label htmlFor='phoneNumber' className='block text-sm font-medium mb-1'>
          Phone Number
        </label>
        <input
          type='text'
          id='phoneNumber'
          {...register('phoneNumber')}
          className='w-full p-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        />
      </div>
    </>
  );
};

export default StepOne;

StepTwo.js

Create a new file named StepTwo.js inside the src directory. This component will handle the second step of the form:

import React from 'react';
import { useFormContext } from 'react-hook-form';

const StepTwo = () => {
  const { register } = useFormContext();

  return (
    <>
      <h2 className='text-lg font-medium mb-4'>Step 2: Additional Information</h2>
      <div className='mb-4'>
        <label htmlFor='address' className='block text-sm font-medium mb-1'>
          Address
        </label>
        <input
          type='text'
          id='address'
          {...register('address')}
          className='w-full p-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        />
      </div>
      <div className='mb-4'>
        <label htmlFor='city' className='block text-sm font-medium mb-1'>
          City
        </label>
        <input
          type='text'
          id='city'
          {...register('city')}
          className='w-full p-2

 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        />
      </div>
      <div className='mb-4'>
        <label htmlFor='zipCode' className='block text-sm font-medium mb-1'>
          ZIP Code
        </label>
        <input
          type='text'
          id='zipCode'
          {...register('zipCode')}
          className='w-full p-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        />
      </div>
      <div>
        <label htmlFor='country' className='block text-sm font-medium mb-1'>
          Country
        </label>
        <input
          type='text'
          id='country'
          {...register('country')}
          className='w-full p-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        />
      </div>
    </>
  );
};

export default StepTwo;

StepThree.js

Create a new file named StepThree.js inside the src directory. This component will handle the third and final step of the form:

import React from 'react';
import { useFormContext } from 'react-hook-form';

const StepThree = () => {
  const { register } = useFormContext();

  return (
    <>
      <h2 className='text-lg font-medium mb-4'>Step 3: Confirmation</h2>
      <div className='mb-4'>
        <label htmlFor='comments' className='block text-sm font-medium mb-1'>
          Comments
        </label>
        <textarea
          id='comments'
          {...register('comments')}
          className='w-full p-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
          rows='5'
        />
      </div>
      <div className='mb-4'>
        <label htmlFor='rating' className='block text-sm font-medium mb-1'>
          Rating
        </label>
        <select
          id='rating'
          {...register('rating')}
          className='w-full p-1 border rounded-md focus:outline-none focus:ring focus:border-blue-300'
        >
          <option value='5'>Excellent</option>
          <option value='4'>Good</option>
          <option value='3'>Average</option>
          <option value='2'>Below Average</option>
          <option value='1'>Poor</option>
        </select>
      </div>
      <div>
        <label htmlFor='subscribe' className='block text-sm font-medium mb-1'>
          Subscribe to Newsletter
        </label>
        <input type='checkbox' id='subscribe' {...register('subscribe')} className='mr-2' />
        <span className='text-sm text-gray-600'>Subscribe to our newsletter</span>
      </div>
    </>
  );
};

export default StepThree;

Integrating Steps into MultiStepForm Component

Back in the MultiStepForm.js component, integrate the steps based on the current step state. Use the provided navigation buttons to move between steps. Finally, remember to wrap the form components in a FormProvider and handle the form submission.

With all these pieces in place, you have successfully created a multi-step form in React using the react-hook-form library! This modular approach allows you to manage complex forms more efficiently and provide a better user experience.

Feel free to style and customize the components according to your project's design requirements.

Congratulations on building a functional multi-step form in React! You can now take this knowledge and apply it to more complex forms and interactive user interfaces.

Happy coding! ๐Ÿš€

ย