Reusable Stepper

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

Post Your Comment:

Your email address will not be published. Required fields are marked *