Horje
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.

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




Reffered: https://www.geeksforgeeks.org


ReactJS

Related
How to build and publish an NPM package for React using Typescript? How to build and publish an NPM package for React using Typescript?
What are React Hooks, and why were they added to React? What are React Hooks, and why were they added to React?
Explain the role of middleware in authentication and authorization in Redux. Explain the role of middleware in authentication and authorization in Redux.
What are some common patterns for handling pagination in Redux? What are some common patterns for handling pagination in Redux?
Explain the benefits and challenges of infinite scrolling in Redux. Explain the benefits and challenges of infinite scrolling in Redux.

Type:
Geek
Category:
Coding
Sub Category:
Tutorial
Uploaded by:
Admin
Views:
17