DEV Community

Michael Burrows
Michael Burrows

Posted on • Originally published at w3collective.com

Setup a customisable multi-step form in React

GitHub logo w3collective / react-multi-step-form

Customisable multi-step form in React

In this tutorial we’ll be setting up a multi-step form (also called a wizard form) component in React. Breaking up large forms into multiple steps makes them less daunting for the user to complete. As React is component based this can be achieved by including each step in an individual component.

First let’s setup a new project using Create React App:

npx create-react-app multi-step-form
Enter fullscreen mode Exit fullscreen mode

Next create a components folder in the src directory with the following files:

MultiStep1.js
MultiStep2.js
MultiStep3.js
MultiStepForm.js
MultiStepSubmit.js
Enter fullscreen mode Exit fullscreen mode

We’ll code each of the steps before pulling it all together in MultiStepForm.js.

MultiStep1.js

The first step of the form will capture the name & email:

import React from "react";
const Step1 = (props) => {
  const { data, handleChange, next } = props;
  return (
    <form>
      <p>
        <label htmlFor="name">Name:</label>
        <input
          type="text"
          name="name"
          value={data.name}
          onChange={handleChange}
        />
      </p>
      <p>
        <label htmlFor="email">Email:</label>
        <input
          type="email"
          name="email"
          value={data.email}
          onChange={handleChange}
        />
      </p>
      <button onClick={next}>Next</button>
    </form>
  );
};
export default Step1;
Enter fullscreen mode Exit fullscreen mode

We store the values entered into the fields in the data prop, the handleChange updates the values stored and next loads the next step of the form. The functionality for each of these will come later in MultiStepForm.js.

MultiStep2.js

The second step captures some location data:

import React from "react";
const Step2 = (props) => {
  const { data, handleChange, next, back } = props;
  return (
    <form>
      <p>
        <label htmlFor="street">Street:</label>
        <input
          type="text"
          name="street"
          value={data.street}
          onChange={handleChange}
        />
      </p>
      <p>
        <label htmlFor="city">City:</label>
        <input
          type="text"
          name="city"
          value={data.city}
          onChange={handleChange}
        />
      </p>
      <p>
        <label htmlFor="postcode">Postcode:</label>
        <input
          type="number"
          name="postcode"
          value={data.postcode}
          onChange={handleChange}
        />
      </p>
      <button onClick={back}>Back</button> 
      <button onClick={next}>Next</button>
    </form>
  );
};
export default Step2;
Enter fullscreen mode Exit fullscreen mode

This is the same as the first step except for the inclusion of a back button.

MultiStep3.js

The third step captures a comment:

import React from "react";
const Step3 = (props) => {
  const { data, handleChange, next, back } = props;
  return (
    <form>
      <p>
        <label htmlFor="comments">Comments:</label>
        <textarea
          name="comments"
          value={data.comments}
          onChange={handleChange}
        ></textarea>
      </p>      
      <button onClick={back}>Back</button> 
      <button onClick={next}>Next</button>
    </form>
  );
};
export default Step3;
Enter fullscreen mode Exit fullscreen mode

MultiStepSubmit.js

After each of the steps has been completed we’ll display the data captured:

import React from "react";
const Submit = (props) => {
  const { data } = props;
  const listItems = Object.entries(data).map(([key, value])=>(
    <li>
      <strong>{key}:</strong> {value}
    </li>
  ));
  return (
    <div>
      <ul>{listItems}</ul>
      <button type="submit">Submit</button>
    </div>
  );
};
export default Submit;
Enter fullscreen mode Exit fullscreen mode

This is simply looping through the data and outputting the key and value into an unordered list. We wont be creating the submit functionality in this tutorial there are many ways to go about this. If you would like to see an example of how this data could be sent via email using Node.js check out this tutorial.

MultiStepForm.js

We can now pull it all together in the MultiStepForm component:

import React, { useState } from "react";
import Step1 from "./MultiStep1";
import Step2 from "./MultiStep2";
import Step3 from "./MultiStep3";
import Submit from "./MultiStepSubmit";

const MultiStepForm = () => {
  const [currentStep, setCurrentStep] = useState(1);
  const [formData, setFormData] = useState({
    name: "",
    email: "",
    street: "",
    city: "",
    postcode: "",
    comments: "",    
  });
  const handleChange = (event) => {
    setFormData({
      ...formData,
      [event.target.name]: event.target.value,
    });
  };
  const next = () => {
    setCurrentStep(currentStep + 1);
  };
  const back = () => {
    setCurrentStep(currentStep - 1);
  };
  switch (currentStep) {
    case 1:
      return (
        <Step1 
          data={formData} 
          handleChange={handleChange} 
          next={next} 
        />
      );
    case 2:
      return (
        <Step2
          data={formData}
          handleChange={handleChange}
          next={next}
          back={back}
        />
      );
    case 3:
      return (
        <Step3
          data={formData}
          handleChange={handleChange}
          next={next}
          back={back}
        />
      );
    default:
      return <Submit data={formData} back={back} />;
  }
};
export default MultiStepForm;
Enter fullscreen mode Exit fullscreen mode

As you can see the multi-step functionality is handled by a switch statement that checks what the currentStep is and then renders the component for that step.

If you want to modify or add additional fields you’ll need to update the keys in the formData inline with your new fields. Additional steps can be created by importing a new component and adding it to the switch statement.

All that’s left todo is load the component into the app by modifying App.js as follows:

import MultiStepForm from "./components/MultiStepForm";
import "./App.css";
const App = () => {
  return <MultiStepForm />;
};
export default App;
Enter fullscreen mode Exit fullscreen mode

There you have it, a multi-step form that you can modify to suit your needs. If you enjoyed this tutorial why not check out some of my other tutorials about building custom React components.

Latest comments (2)

Collapse
 
ceoshikhar profile image
Shikhar

How would you handle change for a radiobox? Your handle change works just for text inputs.

Collapse
 
michaelburrows profile image
Michael Burrows

If you wanted to add a gender radio select for example you would first need to add it to the formData state:

const [formData, setFormData] = useState({
    name: "",
    gender: "",
    email: "",
    street: "",
    city: "",
    postcode: "",
    comments: "",    
  });
Enter fullscreen mode Exit fullscreen mode

Then in the form step the radio would be rendered like this:

<p>
        <label htmlFor="name">Male:</label>
        <input
            type="radio"
            name="gender"
            value="male"
            checked={data.gender === "male"}
            onChange={handleChange}            
          />    
        <label htmlFor="name">Female:</label>
        <input
              type="radio"
              name="gender"
              value="female"
              checked={data.gender === "female"}
              onChange={handleChange}            
            />    
      </p>
Enter fullscreen mode Exit fullscreen mode