React Hook Form

Performant form validation for Next.js

📝 What is React Hook Form?

React Hook Form is a performant, flexible form library with easy validation. It minimizes re-renders, reduces code complexity, and provides built-in validation with excellent TypeScript support for building forms in Next.js applications.


// Simple form with React Hook Form
import { useForm } from 'react-hook-form'

function MyForm() {
  const { register, handleSubmit } = useForm()
  
  const onSubmit = (data) => console.log(data)
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('name')} />
      <button type="submit">Submit</button>
    </form>
  )
}
                                    

Key React Hook Form Features

Performance

Minimal re-renders

const { register } = useForm({
  mode: 'onChange'
})

Validation

Built-in validation rules

register('email', {
  required: true,
  pattern: /^\S+@\S+$/
})
🎯

Error Handling

Easy error management

const { errors } = useForm()
{errors.email?.message}
🔗

Integration

Works with UI libraries

import { Controller } from 
'react-hook-form'

🔹 Basic Form Setup

Use the useForm hook to create a form with automatic state management. The register function connects inputs to the form state without controlled components.

// components/ContactForm.jsx
'use client'
import { useForm } from 'react-hook-form'

export default function ContactForm() {
  const { register, handleSubmit, formState: { errors } } = useForm()

  const onSubmit = (data) => {
    console.log(data)
    // Send data to API
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>Name</label>
        <input {...register('name', { required: true })} />
        {errors.name && <span>Name is required</span>}
      </div>

      <div>
        <label>Email</label>
        <input {...register('email', { required: true })} />
        {errors.email && <span>Email is required</span>}
      </div>

      <button type="submit">Submit</button>
    </form>
  )
}

Output:

🔹 Validation Rules

Add validation rules directly to register function. React Hook Form supports required, min, max, pattern, and custom validation with clear error messages.

// components/SignupForm.jsx
'use client'
import { useForm } from 'react-hook-form'

export default function SignupForm() {
  const { register, handleSubmit, formState: { errors } } = useForm()

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <div>
        <input 
          {...register('username', {
            required: 'Username is required',
            minLength: {
              value: 3,
              message: 'Username must be at least 3 characters'
            }
          })} 
          placeholder="Username"
        />
        {errors.username && <p>{errors.username.message}</p>}
      </div>

      <div>
        <input 
          {...register('email', {
            required: 'Email is required',
            pattern: {
              value: /^\S+@\S+$/i,
              message: 'Invalid email address'
            }
          })} 
          placeholder="Email"
        />
        {errors.email && <p>{errors.email.message}</p>}
      </div>

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

      <button type="submit">Sign Up</button>
    </form>
  )
}

🔹 Form with Server Actions

Integrate React Hook Form with Next.js Server Actions for seamless form submission. Handle validation on client and processing on server for secure data handling.

// app/actions.js
'use server'

export async function createUser(data) {
  // Process form data
  console.log('Creating user:', data)
  return { success: true }
}

// components/UserForm.jsx
'use client'
import { useForm } from 'react-hook-form'
import { createUser } from '@/app/actions'

export default function UserForm() {
  const { register, handleSubmit, formState: { isSubmitting } } = useForm()

  const onSubmit = async (data) => {
    const result = await createUser(data)
    if (result.success) {
      alert('User created!')
    }
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('name')} placeholder="Name" />
      <input {...register('email')} placeholder="Email" />
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? 'Submitting...' : 'Submit'}
      </button>
    </form>
  )
}

🔹 Watch Form Values

Monitor form field values in real-time with the watch function. Useful for conditional rendering, live previews, or dependent field validation.

// components/ConditionalForm.jsx
'use client'
import { useForm } from 'react-hook-form'

export default function ConditionalForm() {
  const { register, watch } = useForm()
  const accountType = watch('accountType')

  return (
    <form>
      <select {...register('accountType')}>
        <option value="personal">Personal</option>
        <option value="business">Business</option>
      </select>

      {accountType === 'business' && (
        <div>
          <label>Company Name</label>
          <input {...register('companyName')} />
        </div>
      )}

      <button type="submit">Submit</button>
    </form>
  )
}

🔹 Reset and Default Values

Set default values and reset forms easily. Useful for edit forms, clearing after submission, or restoring initial state.

// components/EditForm.jsx
'use client'
import { useForm } from 'react-hook-form'

export default function EditForm({ user }) {
  const { register, handleSubmit, reset } = useForm({
    defaultValues: {
      name: user.name,
      email: user.email
    }
  })

  const onSubmit = (data) => {
    console.log(data)
    // After successful update
    reset() // Reset to default values
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('name')} />
      <input {...register('email')} />
      <button type="submit">Update</button>
      <button type="button" onClick={() => reset()}>
        Reset
      </button>
    </form>
  )
}

🧠 Test Your Knowledge

What function connects inputs to React Hook Form?