React Checkbox Pro

React Hook Form

How to integrate React Checkbox Pro with React Hook Form and Zod validation

React Hook Form Integration

Learn how to integrate React Checkbox Pro with React Hook Form for form management and validation.

Installation

Install dependencies

npm install react-hook-form @hookform/resolvers zod
# or
yarn add react-hook-form @hookform/resolvers zod
# or
pnpm add react-hook-form @hookform/resolvers zod

Import required components

import { useForm, Controller } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Checkbox, CheckboxGroup } from "react-checkbox-pro";

Form Schema

First, define your form schema using Zod:

import * as z from "zod";
 
export const checkboxFormSchema = z.object({
  acceptTerms: z.boolean().refine(val => val === true, {
    message: "You must accept the terms and conditions"
  }),
  notifications: z.object({
    email: z.boolean(),
    sms: z.boolean(),
    push: z.boolean()
  }).refine(data => Object.values(data).some(val => val), {
    message: "You must select at least one notification method"
  }),
  interests: z.array(z.string()).min(1, {
    message: "Please select at least one area of interest"
  }),
  subscription: z.enum(["free", "pro", "enterprise"]).optional(),
  marketing: z.boolean().optional(),
});
 
export type CheckboxFormData = z.infer<typeof checkboxFormSchema>;

Complete Example

Here's a comprehensive example showing different ways to use React Checkbox Pro with React Hook Form:

import { useForm, Controller } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Checkbox, CheckboxGroup } from "react-checkbox-pro";
import { checkboxFormSchema, type CheckboxFormData } from "@/lib/validations/checkbox-form.schema";
 
export default function FormExample() {
  const {
    handleSubmit,
    control,
    formState: { errors },
    watch,
  } = useForm<CheckboxFormData>({
    resolver: zodResolver(checkboxFormSchema),
    defaultValues: {
      acceptTerms: false,
      notifications: {
        email: false,
        sms: false,
        push: false,
      },
      interests: [],
      subscription: undefined,
      marketing: false,
    },
  });
 
  const onSubmit = (data: CheckboxFormData) => {
    console.log("Form submitted:", data);
  };
 
  return (
    <div className="min-h-screen bg-gray-50 dark:bg-gray-900 p-8">
      <div className="max-w-2xl mx-auto space-y-8">
        <div className="p-6 rounded-lg shadow-sm bg-white dark:bg-gray-800">
          <h1 className="text-2xl font-bold mb-6">Registration Form</h1>
 
          <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
            {/* Terms and Conditions */}
            <div className="space-y-2">
              <Controller
                name="acceptTerms"
                control={control}
                render={({ field }) => (
                  <Checkbox
                    checked={field.value}
                    onChange={field.onChange}
                    error={!!errors.acceptTerms}
                    errorMessage={errors.acceptTerms?.message}
                  >
                    I accept the terms and conditions
                  </Checkbox>
                )}
              />
            </div>
 
            {/* Notification Preferences */}
            <div className="space-y-4">
              <h2 className="text-lg font-semibold">Notification Preferences</h2>
              <div className="space-y-2">
                <Controller
                  name="notifications.email"
                  control={control}
                  render={({ field }) => (
                    <Checkbox
                      checked={field.value}
                      onChange={field.onChange}
                      error={!!errors.notifications}
                    >
                      Email notifications
                    </Checkbox>
                  )}
                />
                <Controller
                  name="notifications.sms"
                  control={control}
                  render={({ field }) => (
                    <Checkbox
                      checked={field.value}
                      onChange={field.onChange}
                      error={!!errors.notifications}
                    >
                      SMS notifications
                    </Checkbox>
                  )}
                />
                <Controller
                  name="notifications.push"
                  control={control}
                  render={({ field }) => (
                    <Checkbox
                      checked={field.value}
                      onChange={field.onChange}
                      error={!!errors.notifications}
                    >
                      Push notifications
                    </Checkbox>
                  )}
                />
                {errors.notifications && (
                  <p className="text-sm text-red-500 mt-1">
                    {errors.notifications.message}
                  </p>
                )}
              </div>
            </div>
 
            {/* Areas of Interest */}
            <div className="space-y-4">
              <h2 className="text-lg font-semibold">Areas of Interest</h2>
              <Controller
                name="interests"
                control={control}
                render={({ field }) => (
                  <CheckboxGroup
                    value={field.value}
                    onChange={field.onChange}
                    error={!!errors.interests}
                  >
                    <Checkbox value="technology">Technology</Checkbox>
                    <Checkbox value="design">Design</Checkbox>
                    <Checkbox value="business">Business</Checkbox>
                    <Checkbox value="marketing">Marketing</Checkbox>
                  </CheckboxGroup>
                )}
              />
              {errors.interests && (
                <p className="text-sm text-red-500">
                  {errors.interests.message}
                </p>
              )}
            </div>
 
            {/* Subscription Type */}
            <div className="space-y-4">
              <h2 className="text-lg font-semibold">Subscription Type</h2>
              <Controller
                name="subscription"
                control={control}
                render={({ field }) => (
                  <div className="space-y-2">
                    <Checkbox
                      checked={field.value === "free"}
                      onChange={() => field.onChange("free")}
                      color="default"
                    >
                      Free Plan
                    </Checkbox>
                    <Checkbox
                      checked={field.value === "pro"}
                      onChange={() => field.onChange("pro")}
                      color="primary"
                    >
                      Pro Plan
                    </Checkbox>
                    <Checkbox
                      checked={field.value === "enterprise"}
                      onChange={() => field.onChange("enterprise")}
                      color="secondary"
                    >
                      Enterprise Plan
                    </Checkbox>
                  </div>
                )}
              />
            </div>
 
            {/* Marketing Preferences */}
            <div className="space-y-2">
              <Controller
                name="marketing"
                control={control}
                render={({ field }) => (
                  <Checkbox
                    checked={field.value}
                    onChange={field.onChange}
                    color="success"
                  >
                    I want to receive marketing emails
                  </Checkbox>
                )}
              />
            </div>
 
            <button type="submit">Submit</button>
          </form>
        </div>
      </div>
    </div>
  );
}

Usage Patterns

Single Checkbox

<Controller
  name="acceptTerms"
  control={control}
  render={({ field }) => (
    <Checkbox
      checked={field.value}
      onChange={field.onChange}
      error={!!errors.acceptTerms}
      errorMessage={errors.acceptTerms?.message}
    >
      Accept Terms
    </Checkbox>
  )}
/>

Checkbox Group

<Controller
  name="interests"
  control={control}
  render={({ field }) => (
    <CheckboxGroup
      value={field.value}
      onChange={field.onChange}
      error={!!errors.interests}
    >
      <Checkbox value="option1">Option 1</Checkbox>
      <Checkbox value="option2">Option 2</Checkbox>
    </CheckboxGroup>
  )}
/>

Nested Fields

<Controller
  name="notifications.email"
  control={control}
  render={({ field }) => (
    <Checkbox
      checked={field.value}
      onChange={field.onChange}
      error={!!errors.notifications}
    >
      Email notifications
    </Checkbox>
  )}
/>

Best Practices

  1. Form Setup:

    • Use Zod for type-safe schema validation
    • Define proper default values
    • Handle form submission appropriately
  2. Error Handling:

    • Display field-specific error messages
    • Show group-level validation errors
    • Use proper error styling
  3. Performance:

    • Memoize callbacks when needed
    • Use form context for complex forms
    • Avoid unnecessary re-renders
  4. Accessibility:

    • Maintain proper form structure
    • Include proper ARIA attributes
    • Ensure keyboard navigation works

On this page