Open In App

How to create Stepper Component Using React JS ?

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.



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

Step 2: Navigate to the Project Directory

cd stepper

Step 3: Install the project dependencies using:

npm install

Project Structure:

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.




// 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;




// 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;




// 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>
);




/* 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:

output


Article Tags :