React Hook Form

7.72.1 · active · verified Sun Apr 19

React Hook Form is a high-performance, flexible, and extensible forms library for React applications, currently stable at version 7.72.1. It leverages an uncontrolled component approach, minimizing re-renders and improving performance by isolating component updates from form state changes. The library maintains a rapid release cadence, frequently delivering patches and minor versions, with a beta for version 8 already available. Key differentiators include its focus on performance, small bundle size, seamless integration with native HTML form validation, and robust TypeScript support for enhanced type safety across form values and errors. It provides essential hooks like `useForm` for comprehensive form management, `Controller` for integrating with external controlled components, and `useFieldArray` for dynamic lists of inputs, making it suitable for a wide spectrum of form complexities.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates a basic form using `useForm` with TypeScript, `register` for input binding and validation, `handleSubmit` for submission, and `formState.errors` for displaying validation feedback. It includes required fields, email pattern validation, and minimum age constraint.

import React from 'react';
import { useForm } from 'react-hook-form';

type FormData = {
  firstName: string;
  lastName: string;
  email: string;
  age: number;
};

export default function MyForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>({
    defaultValues: {
      firstName: '',
      lastName: '',
      email: '',
      age: 18,
    },
  });

  const onSubmit = (data: FormData) => {
    console.log('Form Submitted:', data);
    // In a real app, you would send this data to an API
    // Example: fetch('/api/submit-form', { method: 'POST', body: JSON.stringify(data) });
    alert(JSON.stringify(data, null, 2));
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)} className="space-y-4 p-4 max-w-md mx-auto bg-white shadow-md rounded-lg">
      <div>
        <label htmlFor="firstName" className="block text-sm font-medium text-gray-700">First Name:</label>
        <input
          id="firstName"
          {...register('firstName', { required: 'First name is required' })}
          className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"
        />
        {errors.firstName && <p className="mt-1 text-sm text-red-600">{errors.firstName.message}</p>}
      </div>

      <div>
        <label htmlFor="lastName" className="block text-sm font-medium text-gray-700">Last Name:</label>
        <input
          id="lastName"
          {...register('lastName', { required: 'Last name is required' })}
          className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"
        />
        {errors.lastName && <p className="mt-1 text-sm text-red-600">{errors.lastName.message}</p>}
      </div>

      <div>
        <label htmlFor="email" className="block text-sm font-medium text-gray-700">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' }
          })}
          className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"
        />
        {errors.email && <p className="mt-1 text-sm text-red-600">{errors.email.message}</p>}
      </div>

      <div>
        <label htmlFor="age" className="block text-sm font-medium text-gray-700">Age:</label>
        <input
          id="age"
          type="number"
          {...register('age', { required: 'Age is required', min: { value: 18, message: 'Must be at least 18' } })}
          className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"
        />
        {errors.age && <p className="mt-1 text-sm text-red-600">{errors.age.message}</p>}
      </div>

      <button
        type="submit"
        className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
      >
        Submit
      </button>
    </form>
  );
}

view raw JSON →