Reusable Stepper with React and Tailwindcss
This Stepper is base off Eugene Costov video below, I just changed a few this like making it a full function base stepper using react hooks and use tailwindcss to style the stepper.
if (document.getElementById('Stepper')) { ReactDOM.render(<Wizard />, document.getElementById('Stepper')); } // index.js
import React, { useState } from 'react' import Stepper from './components/wizard/Stepper' function Wizard() { const [currentStep, setCurrentStep] = useState(1); const stepArray = [ "Company Details", // "Location", // "Service Offered", "Business Hours", "Complete" ]; const handleClick = (clickType) => { let newStep = currentStep; (clickType == "next") ? newStep++ : newStep--; // Check if steps are within the boundary if (newStep > 0 && newStep <= stepArray.length) { setCurrentStep(newStep) } } return ( <> <div className="container horizontal mt-5 mb-12"> <Stepper steps={stepArray} currentStepNumber={currentStep} /> </div> <div className="container flex justify-around my-8 "> <button onClick={() => handleClick()} className="btn-primary transition duration-300 ease-in-out focus:outline-none focus:shadow-outline bg-orange-700 hover:bg-orange-900 text-white font-normal py-2 px-4 mr-1 rounded"> Previous </button> <button onClick={() => handleClick("next")} className="btn-outline-primary transition duration-300 ease-in-out focus:outline-none focus:shadow-outline border border-orange-700 hover:bg-orange-700 text-orange-700 hover:text-white font-normal py-2 px-4 rounded"> Next </button> </div> </> ) } export default Wizard //Wizard.js
import React, { useState, useEffect, useRef } from 'react' const Stepper = ({ steps, currentStepNumber }) => { const [stepperSteps, setStep] = useState([]); const stepsStateRef = useRef(); useEffect(() => { const stepsState = steps.map((step, index) => { const stepObj = {}; stepObj.description = step; stepObj.completed = false; stepObj.highlighted = index === 0 ? true : false; stepObj.selected = index === 0 ? true : false; return stepObj; }); stepsStateRef.current = stepsState; const currentSteps = updateStep(currentStepNumber - 1, stepsState) setStep(currentSteps) }, []); useEffect(() => { const currentSteps = updateStep(currentStepNumber - 1, stepsStateRef.current) setStep(currentSteps) }, [currentStepNumber]); function updateStep(stepNumber, steps) { const newSteps = [...steps]; let stepCounter = 0; while (stepCounter < newSteps.length) { //current step if (stepCounter === stepNumber) { newSteps[stepCounter] = { ...newSteps[stepCounter], highlighted: true, selected: true, completed: false }; stepCounter++; } // Past step else if (stepCounter < stepNumber) { newSteps[stepCounter] = { ...newSteps[stepCounter], highlighted: false, selected: true, completed: true }; stepCounter++; } // Future steps else { newSteps[stepCounter] = { ...newSteps[stepCounter], highlighted: false, selected: false, completed: false } stepCounter++; } } return newSteps } const stepsDisplay = stepperSteps.map((step, index) => { return ( <div key={index} className={index !== stepperSteps.length - 1 ? "w-full flex items-center" : "flex items-center"} > <div className="relative flex flex-col items-center text-teal-600"> <div className={`rounded-full transition duration-500 ease-in-out border-2 border-gray-300 h-12 w-12 flex items-center justify-center py-3 ${step.selected ? "bg-red-600 text-white font-bold" : ""}`}> {step.completed ? <span className="text-white font-bold text-xl">✓</span> : index + 1} </div> <div className={`absolute top-0 text-center mt-16 w-32 text-xs font-medium uppercase ${step.highlighted ? "text-gray-900" : "text-gray-400"}`}> {step.description} </div> </div> <div className="flex-auto border-t-2 transition duration-500 ease-in-out border-gray-300 "> </div> </div> ) }) return ( <div className="mx-4 p-4 flex justify-between items-center"> {stepsDisplay} </div> ) } export default Stepper //Stepper.js
2 thoughts on “Reusable Stepper with React and Tailwindcss”