Skip to main content
Course/Module 8/Topic 2 of 4Intermediate

React Hook Form

Master React Hook Form for efficient form handling with minimal re-renders and built-in validation

80 minBy Priygop TeamLast updated: Feb 2026

What is React Hook Form?

React Hook Form is a performant, flexible and extensible form library with easy-to-use validation. It reduces the amount of code you need to write while removing unnecessary re-renders.

Basic Form Setup

Example
// Install React Hook Form
npm install react-hook-form

// Basic form
import { useForm } from 'react-hook-form';

function BasicForm() {
    const {
        register,
        handleSubmit,
        formState: { errors, isSubmitting },
        reset,
    } = useForm();

    const onSubmit = async (data) => {
        console.log('Form data:', data);
        // Handle form submission
        try {
            await fetch('/api/submit', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data),
            });
            reset(); // Reset form after successful submission
        } catch (error) {
            console.error('Submission failed:', error);
        }
    };

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <div>
                <label htmlFor="name">Name</label>
                <input
                    id="name"
                    {...register('name', { 
                        required: 'Name is required',
                        minLength: { value: 2, message: 'Name must be at least 2 characters' }
                    })}
                />
                {errors.name && <span className="error">{errors.name.message}</span>}
            </div>

            <div>
                <label htmlFor="email">Email</label>
                <input
                    id="email"
                    type="email"
                    {...register('email', {
                        required: 'Email is required',
                        pattern: {
                            value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
                            message: 'Invalid email address'
                        }
                    })}
                />
                {errors.email && <span className="error">{errors.email.message}</span>}
            </div>

            <div>
                <label htmlFor="password">Password</label>
                <input
                    id="password"
                    type="password"
                    {...register('password', {
                        required: 'Password is required',
                        minLength: { value: 8, message: 'Password must be at least 8 characters' }
                    })}
                />
                {errors.password && <span className="error">{errors.password.message}</span>}
            </div>

            <button type="submit" disabled={isSubmitting}>
                {isSubmitting ? 'Submitting...' : 'Submit'}
            </button>
        </form>
    );
}

Advanced Form Features

Example
// Advanced React Hook Form features
import { useForm, Controller } from 'react-hook-form';

// Form with custom validation
function AdvancedForm() {
    const {
        control,
        register,
        handleSubmit,
        formState: { errors, isValid, isDirty },
        watch,
        setValue,
        getValues,
        trigger,
    } = useForm({
        mode: 'onChange', // Validate on change
        criteriaMode: 'all', // Show all validation errors
    });

    const watchedPassword = watch('password');

    const onSubmit = async (data) => {
        console.log('Form data:', data);
    };

    // Custom validation function
    const validatePassword = (value) => {
        if (!value) return 'Password is required';
        if (value.length < 8) return 'Password must be at least 8 characters';
        if (!/[A-Z]/.test(value)) return 'Password must contain at least one uppercase letter';
        if (!/[a-z]/.test(value)) return 'Password must contain at least one lowercase letter';
        if (!/[0-9]/.test(value)) return 'Password must contain at least one number';
        return true;
    };

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <div>
                <label htmlFor="username">Username</label>
                <input
                    id="username"
                    {...register('username', {
                        required: 'Username is required',
                        minLength: { value: 3, message: 'Username must be at least 3 characters' },
                        pattern: {
                            value: /^[a-zA-Z0-9_]+$/,
                            message: 'Username can only contain letters, numbers, and underscores'
                        }
                    })}
                />
                {errors.username && <span className="error">{errors.username.message}</span>}
            </div>

            <div>
                <label htmlFor="password">Password</label>
                <input
                    id="password"
                    type="password"
                    {...register('password', {
                        validate: validatePassword
                    })}
                />
                {errors.password && <span className="error">{errors.password.message}</span>}
            </div>

            <div>
                <label htmlFor="confirmPassword">Confirm Password</label>
                <input
                    id="confirmPassword"
                    type="password"
                    {...register('confirmPassword', {
                        required: 'Please confirm your password',
                        validate: (value) => value === watchedPassword || 'Passwords do not match'
                    })}
                />
                {errors.confirmPassword && <span className="error">{errors.confirmPassword.message}</span>}
            </div>

            {/* Using Controller for complex inputs */}
            <div>
                <label htmlFor="country">Country</label>
                <Controller
                    name="country"
                    control={control}
                    rules={{ required: 'Country is required' }}
                    render={({ field }) => (
                        <select {...field}>
                            <option value="">Select a country</option>
                            <option value="us">United States</option>
                            <option value="ca">Canada</option>
                            <option value="uk">United Kingdom</option>
                            <option value="au">Australia</option>
                        </select>
                    )}
                />
                {errors.country && <span className="error">{errors.country.message}</span>}
            </div>

            <div>
                <label htmlFor="bio">Bio</label>
                <Controller
                    name="bio"
                    control={control}
                    rules={{ maxLength: { value: 500, message: 'Bio must be less than 500 characters' } }}
                    render={({ field }) => (
                        <textarea
                            {...field}
                            placeholder="Tell us about yourself..."
                            rows={4}
                        />
                    )}
                />
                {errors.bio && <span className="error">{errors.bio.message}</span>}
            </div>

            <button type="submit" disabled={!isValid || !isDirty}>
                Submit
            </button>

            <button type="button" onClick={() => trigger()}>
                Validate All
            </button>
        </form>
    );
}

Additional Resources

Recommended Reading

  • React Query Documentation
  • React Hook Form Guide
  • Framer Motion Tutorial

Online Resources

  • React Ecosystem Overview
  • Popular React Libraries
  • React Query Best Practices
Chat on WhatsApp
Priygop - Leading Professional Development Platform | Expert Courses & Interview Prep