Open In App

How to create Stepper Component Using React JS ?

Last Updated : 15 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

The checkout process on e-commerce websites often involves a series of steps, commonly represented by a stepper component. In this tutorial, we will guide you through creating a customizable stepper component using React, allowing you to easily integrate it into your web applications.

Preview of final output: Let us have a look at how the final output will look like.

resize-1707908967217026262dke

Project Preview

Prerequisites

Approach

Our approach will involve a configuration-driven UI, where we define the steps and their corresponding components in a configuration object. This allows for flexibility and easy customization. We will count each step and accordingly the completion graph will change and all passing through all the steps it will shows the completion of the stepper.

Steps to Create the React Application

Step 1: Set Up Your React App with Vite

npm create vite@latest

hjk

Step 2: Navigate to the Project Directory

cd stepper

Step 3: Install the project dependencies using:

npm install

Project Structure:

Screenshot-2024-02-12-174908

project structure

Dependencies:

"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19",
"@vitejs/plugin-react-swc": "^3.5.0",
"eslint": "^8.56.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"vite": "^5.1.0"
}

Example: Create the required files and add the following code.

Javascript




// CheckoutStepper.jsx
 
import { useEffect, useRef, useState } from "react";
 
const CheckoutStepper = ({ stepsConfig = [] }) => {
    const [currentStep, setCurrentStep] = useState(1);
    const [isComplete, setIsComplete] = useState(false);
    const [margins, setMargins] = useState({
        marginLeft: 0,
        marginRight: 0,
    });
    const stepRef = useRef([]);
 
    useEffect(() => {
        setMargins({
            marginLeft: stepRef.current[0].offsetWidth / 2,
            marginRight: stepRef.current[stepsConfig.length - 1].offsetWidth / 2,
        });
    }, [stepRef, stepsConfig.length]);
 
    if (!stepsConfig.length) {
        return <></>;
    }
 
    const handleNext = () => {
        setCurrentStep((prevStep) => {
            if (prevStep === stepsConfig.length) {
                setIsComplete(true);
                return prevStep;
            } else {
                return prevStep + 1;
            }
        });
    };
 
    const calculateProgressBarWidth = () => {
        return ((currentStep - 1) / (stepsConfig.length - 1)) * 100;
    };
 
    const ActiveComponent = stepsConfig[currentStep - 1]?.Component;
 
    return (
        <>
            <div className="stepper">
                {stepsConfig.map((step, index) => {
                    return (
                        <div
                            key={step.name}
                            ref={(el) => (stepRef.current[index] = el)}
                            className={`step ${currentStep >
                                                index + 1 || isComplete ?
                                "complete" : ""
                                } ${currentStep === index + 1 ? "active" : ""} `}
                        >
                            <div className="step-number">
                                {currentStep > index + 1 || isComplete ? (
                                    <span>&#10003;</span>
                                ) : (
                                    index + 1
                                )}
                            </div>
                            <div className="step-name">{step.name}</div>
                        </div>
                    );
                })}
 
                <div
                    className="progress-bar"
                    style={{
                        width: `calc(100% - ${margins.marginLeft
                                    + margins.marginRight}px)`,
                        marginLeft: margins.marginLeft,
                        marginRight: margins.marginRight,
                    }}
                >
                    <div
                        className="progress"
                        style={{ width: `${calculateProgressBarWidth()}%` }}
                    ></div>
                </div>
            </div>
 
            <ActiveComponent />
 
            {!isComplete && (
                <button className="btn" onClick={handleNext}>
                    {currentStep === stepsConfig.length ? "Finish" : "Next"}
                </button>
            )}
        </>
    );
};
 
export default CheckoutStepper;


Javascript




// App.jsx
 
import "./App.css";
import CheckoutStepper from "./components/CheckoutStepper";
 
const CHECKOUT_STEPS = [
  {
    name: "Customer Info",
    Component: () => <div>Provide your contact details.</div>,
  },
  {
    name: "Shipping Info",
    Component: () => <div>Enter your shipping address.</div>,
  },
  {
    name: "Payment",
    Component: () => <div>Complete payment for your order.</div>,
  },
  {
    name: "Delivered",
    Component: () => <div> Your order has been delivered.</div>,
  },
];
 
function App() {
  return (
    <div>
      <h2>Checkout</h2>
      <CheckoutStepper stepsConfig={CHECKOUT_STEPS} />
    </div>
  );
}
 
export default App;


Javascript




// main.jsx
 
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
 
ReactDOM.createRoot(document.getElementById("root")).render(
    <React.StrictMode>
        <App />
    </React.StrictMode>
);


CSS




/* App.css */
 
body {
    font-family: sans-serif;
}
 
.stepper {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
}
 
.step {
    display: flex;
    flex-direction: column;
    align-items: center;
}
 
.step-number {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background-color: #ccc;
    display: flex;
    justify-content: center;
    align-items: center;
    margin-bottom: 5px;
    z-index: 2;
}
 
.step-name {
    font-size: 14px;
}
 
.active .step-number {
    background-color: #007bff;
    color: #fff;
}
 
.complete .step-number {
    background-color: #28a745;
    color: #fff;
}
 
.progress-bar {
    position: absolute;
    top: 25%;
    left: 0;
    height: 4px;
    background-color: #ccc;
}
 
.progress {
    height: 100%;
    background-color: #28a745;
    transition: 0.2s ease;
}


Steps to run the application:

Step 1: Type the following command in the terminal.

npm run dev

Step 2: Open web browser and type the following URL.

http://localhost:5173/

Output:

Recording2024-02-12175319-ezgifcom-video-to-gif-converter

output



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads