Stepper Context and Usage
Multi-Step Form System Documentation
Section titled “Multi-Step Form System Documentation”This documentation provides a complete overview of the MultiStepForm component, the GenericStepper context, and a step-by-step guide to creating your own custom multi-step forms. This system is designed to be highly flexible and type-safe, allowing for the creation of complex, multi-step user input flows with minimal boilerplate.
MultiStepForm Component
Section titled “MultiStepForm Component”The MultiStepForm is a generic and reusable React component that orchestrates a multi-step form experience. It manages the display of steps, navigation between them, data accumulation, and final submission. It’s designed to be decoupled from the state management logic, which is provided via a context system.
Props (MultiStepFormProps<T>)
Section titled “Props (MultiStepFormProps<T>)”These are the props accepted by the MultiStepForm component:
| Prop | Type | Description |
|---|---|---|
steps | StepConfig<T>[] | An ordered array of step configuration objects. Each object defines a label for the indicator and the component to render for that step. |
onFinish | (data: T) => void | A callback function that is invoked with the accumulated form data when the user clicks the “Submit” button on the final step. |
ContextProvider | React.FC<{ initialData?: T; children: React.ReactNode }> | The Provider component from your created stepper context. This will wrap the form and provide the state. |
useStepperHook | () => StepperContextValue<T> | The hook from your created stepper context. The form uses this to access state and control navigation. |
initialData | T (optional) | An optional object containing the initial data for the form. |
The MultiStepForm component relies on several TypeScript types to ensure type safety and a clear development experience.
CommonStepProps<T>
Section titled “CommonStepProps<T>”This interface defines the props that are automatically passed to every step component you create.
data: T: The current, accumulated data object for the entire form.Tis a generic type representing your form’s data structure.update: (u: Partial<T>) => void: A function to update the form’s data. You pass it a partial object of your data structure, and it will be merged into the current state.
FormStep<T>
Section titled “FormStep<T>”This is a type alias for a React component that conforms to the required props structure for a step.
TypeScript
export type FormStep<T> = React.ComponentType<CommonStepProps<T>>;StepConfig<T>
Section titled “StepConfig<T>”This interface defines the shape of the objects you’ll use to configure each step in the steps array.
label: string: The text label for the step, which is displayed in theStepIndicator.component: FormStep<T>: The React component that will be rendered for this step.
Internal Components
Section titled “Internal Components”The MultiStepForm contains two key internal components:
StepIndicator
Section titled “StepIndicator”A visual component that displays the user’s progress through the form steps. It renders a series of numbered circles, highlighting the current, completed, and upcoming steps.
This is the core functional component that:
- Renders the current active step component.
- Provides “Back” and “Next”/“Submit” buttons for navigation.
- Handles form validation using the browser’s built-in HTML5 validation API before proceeding to the next step.
- Calls the
onFinishfunction on the final step.
GenericStepper Context
Section titled “GenericStepper Context”The GenericStepper provides the state management for the MultiStepForm through a factory function that creates a typed React Context, Provider, and hook.
createStepperContext<T>()
Section titled “createStepperContext<T>()”This factory function is the heart of the state management system. You call it once per form type to generate a dedicated set of context tools.
- Generic
T: You must provide a type argument that represents the data structure of your form (e.g.,createStepperContext<BusinessDetail>()).
Returns: An object containing:
Provider: A React component that you’ll use to wrap yourMultiStepForm. It initializes and manages the form’s state (activeStep,data).useStepper: A custom hook that allows your step components to access and manipulate the form’s state.
StepperContextValue<T>
Section titled “StepperContextValue<T>”This interface defines the shape of the value provided by the stepper context.
activeStep: number: The index of the currently active step.setActiveStep: (step: number) => void: A function to programmatically change the active step.data: T: The accumulated data object for the form.update: (partial: Partial<T>) => void: A function to merge partial updates into the form data.
Complete Usage Guide: Creating a Custom Multi-Step Form
Section titled “Complete Usage Guide: Creating a Custom Multi-Step Form”Here’s how to use these components together to create a fully functional, custom multi-step form.
1. Define Your Form’s Data Structure
Section titled “1. Define Your Form’s Data Structure”First, create an interface or type that defines the shape of the data you want to collect.
Example: BusinessDetail.ts
TypeScript
export interface BusinessDetail { name: string; clientNumber: string; logoUrl: string; summary: string; industryType: string; website: string; employeeCount: number; // ... add other fields as needed}2. Create a Typed Stepper Context
Section titled “2. Create a Typed Stepper Context”Next, use the createStepperContext factory to generate a specific Provider and hook for your form data type.
Example: businessStepper.ts
TypeScript
import { createStepperContext } from "@/components/MultiStepForm/GenericStepper";import { BusinessDetail } from "../data/businessDetail";
// Create and export a dedicated Provider and hookexport const { Provider: BusinessStepperProvider, useStepper: useBusinessStepper,} = createStepperContext<BusinessDetail>();3. Create Your Step Components
Section titled “3. Create Your Step Components”Now, create the individual React components for each step of your form. Each component must be of type FormStep<T> and will receive data and update as props.
Example: Step1_Basic.tsx
TypeScript
import React from "react";import { FormStep } from "@/components/MultiStepForm";import { BusinessDetail } from "@/modules/BusinessManager/data/businessDetail";
const Step1_Basic: FormStep<BusinessDetail> = ({ data, update }) => { return ( <> <legend>Business Info</legend> <label> Name <input value={data.name ?? ""} onChange={(e) => update({ name: e.target.value })} type="text" required /> </label> <label> Client Number <input value={data.clientNumber ?? ""} onChange={(e) => update({ clientNumber: e.target.value })} type="text" required /> </label> {/* ... other input fields ... */} </> );};
export default Step1_Basic;4. Configure Your Steps
Section titled “4. Configure Your Steps”Create an array of StepConfig<T> objects. This array defines the order of your steps, their labels, and the component to render for each one.
Example: In your form implementation file
TypeScript
import { StepConfig } from "@/components/MultiStepForm";import { BusinessDetail } from "@/modules/BusinessManager/data/businessDetail";import Step1_Basic from "./Step1_Basic";import Step2_Contacts from "./Step2_Contacts";// ... import other steps
const STEPS: Array<StepConfig<BusinessDetail>> = [ { label: "Basic", component: Step1_Basic }, { label: "Contacts", component: Step2_Contacts }, // ... other step configurations] as const;5. Implement the MultiStepForm
Section titled “5. Implement the MultiStepForm”Finally, put everything together by rendering the MultiStepForm component. Pass it the steps array, your onFinish handler, and the custom ContextProvider and useStepperHook you created.
Example: NewBusinessForm.tsx
TypeScript
import { MultiStepForm, StepConfig } from "@/components/MultiStepForm";import { BusinessDetail } from "@/modules/BusinessManager/data/businessDetail";import { BusinessStepperProvider, useBusinessStepper,} from "@/modules/BusinessManager/context/businessStepper";import Step1_Basic from "./Step1_Basic";// ... other imports
// Define the steps arrayconst STEPS: Array<StepConfig<BusinessDetail>> = [ { label: "Basic", component: Step1_Basic }, // ... other steps];
interface NewBusinessFormProps { onClose?: () => void; onSubmit: (data: BusinessDetail) => void;}
export default function NewBusinessForm({ onClose, onSubmit,}: NewBusinessFormProps) { return ( // You can wrap the form in other components like a modal <FormModal onClose={onClose} title="Add a new business"> <MultiStepForm<BusinessDetail> steps={STEPS} onFinish={onSubmit} ContextProvider={BusinessStepperProvider} useStepperHook={useBusinessStepper} /> </FormModal> );}By following these steps, you can easily create robust and maintainable multi-step forms tailored to any data structure you need.