- Published on
Working with Multiple Checkboxes in Next.js 14 Using Zod, ShadCN/UI, and React-Hook-Form
- Authors
- Name
- Ripal & Zalak
Introduction
Handling multiple checkboxes in forms can be tricky, especially when working with tools like Next.js 14, Zod, ShadCN/UI, and React-Hook-Form. Whether you’re building a reservation system or a survey form, the combination of these libraries can simplify form handling and validation. This blog provides a detailed approach to manage multiple checkboxes effectively.
Why Use React-Hook-Form with Zod and ShadCN/UI?
- React-Hook-Form: Lightweight and performant form library.
- Zod: Schema validation with type safety.
- ShadCN/UI: Provides pre-styled UI components, including checkboxes.
Setting Up the Environment
Before diving into code, ensure you have the following installed:
- Next.js 14
- React-Hook-Form
- Zod
- ShadCN/UI
npm install next react-hook-form @hookform/resolvers zod shadcn-ui
Creating a Multi-Checkbox Form
1. Define the Zod Schema
The schema ensures the selected checkboxes are validated correctly.
import { z } from 'zod'
export const formSchema = z.object({
reservationMethod: z.array(z.string()).min(1, 'Select at least one option.'),
})
2. Build the Form Component
Use React-Hook-Form to manage form state and validation.
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Checkbox } from '@/components/ui/checkbox';
import { formSchema } from '@/schemas/formSchema';
const ReservationForm = () => {
const {
control,
handleSubmit,
formState: { errors },
} = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
reservationMethod: [],
},
});
const onSubmit = (data: any) => {
console.log(data);
};
const options = [
{ id: 'tourOperator', label: 'Tour Operator' },
{ id: 'internet', label: 'Internet' },
{ id: 'resort', label: 'Directly with the Resort' },
{ id: 'travelAgent', label: 'Travel Agent' },
];
return (
<form onSubmit={handleSubmit(onSubmit)}>
<h2>Select Reservation Methods</h2>
<div className="flex flex-col gap-4">
{options.map((option) => (
<Controller
key={option.id}
name="reservationMethod"
control={control}
render={({ field }) => (
<div className="flex items-center gap-2">
<Checkbox
id={option.id}
checked={field.value.includes(option.label)}
onCheckedChange={(checked) => {
const updatedValues = checked
? [...field.value, option.label]
: field.value.filter((value) => value !== option.label);
field.onChange(updatedValues);
}}
/>
<label htmlFor={option.id}>{option.label}</label>
</div>
)}
/>
))}
{errors.reservationMethod && (
<p className="text-red-500">{errors.reservationMethod.message}</p>
)}
</div>
<button type="submit" className="mt-4 bg-blue-500 text-white py-2 px-4">
Submit
</button>
</form>
);
};
export default ReservationForm;
3. Add Styling
ShadCN/UI provides a robust set of components. Ensure your CSS is configured to handle the UI components properly.
/* Example CSS */
.checkbox {
appearance: none;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
display: inline-block;
cursor: pointer;
}
.checkbox:checked {
background-color: #4a90e2;
border-color: #4a90e2;
}
Handling Additional Fields
If you need dynamic fields based on checkbox selection, React-Hook-Form makes it easy. For instance:
{options.map((option) => (
<Controller
key={option.id}
name="reservationMethod"
control={control}
render={({ field }) => (
<div className="flex items-center gap-2">
<Checkbox
id={option.id}
checked={field.value.includes(option.label)}
onCheckedChange={(checked) => {
const updatedValues = checked
? [...field.value, option.label]
: field.value.filter((value) => value !== option.label);
field.onChange(updatedValues);
}}
/>
<label htmlFor={option.id}>{option.label}</label>
{option.id === 'travelAgent' && field.value.includes(option.label) && (
<input
type="text"
placeholder="Name of agency"
className="border p-2"
/>
)}
</div>
)}
/>
))}
Conclusion
Combining Next.js 14, Zod, ShadCN/UI, and React-Hook-Form simplifies form handling and validation. By following the steps above, you can build dynamic, type-safe forms with ease.