Introducing the Multi-Step Form Component for Makerkit

We're excited to announce the release of the Multi-Step Form Component for Makerkit. This component allows you to create multi-step forms with ease.

I am super excited to announce the release of the Multi-Step Form Component for Makerkit. This component allows you to create multi-step forms with ease.

If you want to know how it's implemented, check out the blog post that explains how to use the Multi-Step Form Component in your projects.

Usage of the Multi-Step Form Component

The component is a wrapper around React Hook Form, Zod and Shadcn UI - it provides a simple API to create multi-step forms with ease.

Here's a simple example of how you can use the Multi-Step Form Component, which we use in conjunction with our built-in Stepper component:

'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { Button } from '@kit/ui/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@kit/ui/form';
import { Input } from '@kit/ui/input';
import {
MultiStepForm,
MultiStepFormContextProvider,
MultiStepFormHeader,
MultiStepFormStep,
createStepSchema,
useMultiStepFormContext,
} from '@kit/ui/multi-step-form';
import { Stepper } from '@kit/ui/stepper';
const FormSchema = createStepSchema({
account: z.object({
username: z.string().min(3),
email: z.string().email(),
}),
profile: z.object({
password: z.string().min(8),
age: z.coerce.number().min(18),
}),
});
type FormValues = z.infer<typeof FormSchema>;
export function MultiStepFormDemo() {
const form = useForm<FormValues>({
resolver: zodResolver(FormSchema),
defaultValues: {
account: {
username: '',
email: '',
},
profile: {
password: '',
},
},
reValidateMode: 'onBlur',
mode: 'onBlur',
});
const onSubmit = (data: FormValues) => {
console.log('Form submitted:', data);
};
return (
<MultiStepForm
className={'space-y-10 p-8 rounded-xl border'}
schema={FormSchema}
form={form}
onSubmit={onSubmit}
>
<MultiStepFormHeader
className={'flex w-full flex-col justify-center space-y-6'}
>
<h2 className={'text-xl font-bold'}>Create your account</h2>
<MultiStepFormContextProvider>
{({ currentStepIndex }) => (
<Stepper
variant={'numbers'}
steps={['Account', 'Profile', 'Review']}
currentStep={currentStepIndex}
/>
)}
</MultiStepFormContextProvider>
</MultiStepFormHeader>
<MultiStepFormStep name="account">
<AccountStep />
</MultiStepFormStep>
<MultiStepFormStep name="profile">
<ProfileStep />
</MultiStepFormStep>
<MultiStepFormStep name="review">
<ReviewStep />
</MultiStepFormStep>
</MultiStepForm>
);
}
function AccountStep() {
const { form, nextStep, isStepValid } = useMultiStepFormContext();
return (
<Form {...form}>
<div className={'flex flex-col gap-4'}>
<FormField
name="account.username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="account.email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end">
<Button onClick={nextStep} disabled={!isStepValid()}>
Next
</Button>
</div>
</div>
</Form>
);
}
function ProfileStep() {
const { form, nextStep, prevStep } = useMultiStepFormContext();
return (
<Form {...form}>
<div className={'flex flex-col gap-4'}>
<FormField
name="profile.password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="profile.age"
render={({ field }) => (
<FormItem>
<FormLabel>Age</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end space-x-2">
<Button type={'button'} variant={'outline'} onClick={prevStep}>
Previous
</Button>
<Button onClick={nextStep}>Next</Button>
</div>
</div>
</Form>
);
}
function ReviewStep() {
const { prevStep, form } = useMultiStepFormContext<typeof FormSchema>();
const values = form.getValues();
return (
<div className={'flex flex-col space-y-4'}>
<div className={'flex flex-col space-y-4'}>
<div>Great! Please review the values.</div>
<div className={'flex flex-col space-y-2 text-sm'}>
<div>
<span>Username</span>: <span>{values.account.username}</span>
</div>
<div>
<span>Email</span>: <span>{values.account.email}</span>
</div>
<div>
<span>Age</span>: <span>{values.profile.age}</span>
</div>
</div>
</div>
<div className="flex justify-end space-x-2">
<Button type={'button'} variant={'outline'} onClick={prevStep}>
Back
</Button>
<Button type={'submit'}>Create Account</Button>
</div>
</div>
);
}

In the example above we have a simple multi-step form with three steps: account, profile and review. Each step is a separate component that renders the form fields for that step.

The MultiStepForm component takes care of managing the form state and transitions between steps. It also provides a simple API to access the form state and navigate between steps.

I hope you enjoy using the Multi-Step Form Component as much as I enjoyed building it. If you have any feedback or suggestions, feel free to reach out to on our Discord!