Tab Form Component in React
Building a multi-step tab form in React with hooks and validation.
Tab Form Component in React
import React, { useState } from "react"; function TabForm({ steps, onSubmit }) { const [currentStep, setCurrentStep] = useState(0); const [formData, setFormData] = useState({}); const handleChange = (name, value) => { setFormData((prev) => ({ ...prev, [name]: value })); }; const validateStep = () => { const step = steps[currentStep]; return step.fields.every((field) => !field.required || formData[field.name]); }; const next = () => { if (!validateStep()) { alert("Please fill all required fields"); return; } if (currentStep < steps.length - 1) setCurrentStep(currentStep + 1); }; const prev = () => { if (currentStep > 0) setCurrentStep(currentStep - 1); }; const handleSubmit = () => { if (!validateStep()) { alert("Please fill all required fields"); return; } onSubmit(formData); }; const step = steps[currentStep]; return ( <div className="tab-form"> <div className="tabs"> {steps.map((s, i) => ( <button key={i} className={`tab ${i === currentStep ? "active" : ""}`} onClick={() => i < currentStep && setCurrentStep(i)} > {i + 1}. {s.title} </button> ))} </div> <div className="tab-content"> {step.fields.map((field) => ( <div key={field.name} className="form-field"> <label>{field.label}</label> <input type={field.type} value={formData[field.name] || ""} onChange={(e) => handleChange(field.name, e.target.value)} /> </div> ))} </div> <div className="actions"> {currentStep > 0 && <button onClick={prev}>Prev</button>} {currentStep < steps.length - 1 ? ( <button onClick={next}>Next</button> ) : ( <button onClick={handleSubmit}>Submit</button> )} </div> </div> ); }
The Takeaway
React tab form: useState for currentStep and formData. handleChange updates formData with spread. validateStep checks required fields. next/prev navigate with validation. handleSubmit calls onSubmit with formData. Tab clicks only allow going back (not forward without validation). Reusable with steps and onSubmit props.
Use useState for currentStep and formData. Define steps as an array of field configs. Render the current step's fields. Validate before next. handleChange updates formData with spread: setFormData(prev => ({ ...prev, [name]: value })).
Use useState with an object: const [formData, setFormData] = useState({}). Update with spread: setFormData(prev => ({ ...prev, [name]: value })). This preserves existing data while adding/updating the changed field.
Write a validateStep function that checks all required fields in the current step: steps[currentStep].fields.every(field => !field.required || formData[field.name]). Call it before next and submit. Show an alert if validation fails.
Allow going back freely: onClick={() => i < currentStep && setCurrentStep(i)}. For going forward, require validation (call next() which validates). This prevents users from jumping to unvalidated steps.
steps (array of { title, fields: [{ name, label, type, required }] }) and onSubmit (callback with formData). This makes the component reusable for any multi-step form. The parent defines the steps and handles submission.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

