React Logoreact-hook-form

React Hook Form is a popular, performant, and flexible library for building forms in React. It's designed to reduce the amount of code you need to write while eliminating unnecessary re-renders, making your forms faster and your development experience smoother.

Key Features and Benefits:

1. Performance: React Hook Form primarily leverages uncontrolled components, meaning it doesn't control the state of your inputs directly in React state. Instead, it relies on the native HTML form elements and their internal state, reducing re-renders and improving performance, especially for large forms.
2. Simplicity & Developer Experience: It provides a straightforward API that's easy to learn and integrate. The core `useForm` hook gives you all the necessary methods to handle form submission, validation, and field registration.
3. Validation: It supports built-in HTML standard validation (e.g., `required`, `minLength`, `pattern`) and can easily integrate with external schema validation libraries like Zod, Yup, Joi, or Superstruct, offering powerful and flexible validation logic.
4. Minimal Re-renders: By isolating component re-renders to only the necessary parts (e.g., error messages), it avoids re-rendering the entire form or parent components unnecessarily.
5. Small Bundle Size: It's a lightweight library, contributing minimally to your application's bundle size.
6. Uncontrolled vs. Controlled: While it promotes uncontrolled components, it also provides a `Controller` component for seamless integration with external controlled UI components (like those from Material-UI, Ant Design, etc.) that don't expose a `ref` prop.

Core Concepts:

* `useForm()`: The primary hook to initialize your form. It returns an object containing various methods and state, such as `register`, `handleSubmit`, `formState: { errors }`, `control`, `watch`, `setValue`, `getValues`, and `reset`.
* `register()`: This function is used to register an input field with React Hook Form. It attaches the necessary event handlers and validation rules (e.g., `required`, `minLength`, `maxLength`, `pattern`, `validate`).
* `handleSubmit(onSubmit, onError)`: A wrapper function for your form's `onSubmit` event. It takes two optional callback functions: `onSubmit` (called with valid form data if validation passes) and `onError` (called with an object of errors if validation fails).
* `formState: { errors }`: An object returned by `useForm()` that contains any validation errors. Its structure typically mirrors your form fields, e.g., `errors.fieldName.message`.
* `control`: An object provided by `useForm()` that is essential for working with external controlled components (e.g., from UI libraries) via the `Controller` component.
* `watch()`: Allows you to subscribe to form value changes without triggering a full re-render of the form component. Useful for conditional rendering or displaying values elsewhere.

Example Code

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

function MyForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();

  const onSubmit = (data) => {
    console.log('Form data:', data);
    alert(`Form submitted! Name: ${data.firstName} ${data.lastName}, Email: ${data.email}, Age: ${data.age}`);
  };

  const onError = (errors) => {
    console.error('Form errors:', errors);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit, onError)} style={{ display: 'flex', flexDirection: 'column', maxWidth: '400px', margin: '20px auto', padding: '20px', border: '1px solid #ccc', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0,0,0,0.1)' }}>
      <h2 style={{ marginBottom: '20px', textAlign: 'center' }}>User Registration</h2>

      <div style={{ marginBottom: '15px' }}>
        <label htmlFor="firstName" style={{ display: 'block', marginBottom: '5px' }}>First Name:</label>
        <input
          id="firstName"
          type="text"
          {...register('firstName', { required: 'First name is required', minLength: { value: 2, message: 'First name must be at least 2 characters' } })}
          style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
        />
        {errors.firstName && <p style={{ color: 'red', fontSize: '0.9em', marginTop: '5px' }}>{errors.firstName.message}</p>}
      </div>

      <div style={{ marginBottom: '15px' }}>
        <label htmlFor="lastName" style={{ display: 'block', marginBottom: '5px' }}>Last Name:</label>
        <input
          id="lastName"
          type="text"
          {...register('lastName', { required: 'Last name is required' })}
          style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
        />
        {errors.lastName && <p style={{ color: 'red', fontSize: '0.9em', marginTop: '5px' }}>{errors.lastName.message}</p>}
      </div>

      <div style={{ marginBottom: '15px' }}>
        <label htmlFor="email" style={{ display: 'block', marginBottom: '5px' }}>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'
            }
          })}
          style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
        />
        {errors.email && <p style={{ color: 'red', fontSize: '0.9em', marginTop: '5px' }}>{errors.email.message}</p>}
      </div>

      <div style={{ marginBottom: '15px' }}>
        <label htmlFor="age" style={{ display: 'block', marginBottom: '5px' }}>Age:</label>
        <input
          id="age"
          type="number"
          {...register('age', {
            required: 'Age is required',
            min: { value: 18, message: 'Must be at least 18 years old' },
            max: { value: 99, message: 'Must be less than 100 years old' }
          })}
          style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
        />
        {errors.age && <p style={{ color: 'red', fontSize: '0.9em', marginTop: '5px' }}>{errors.age.message}</p>}
      </div>

      <button
        type="submit"
        style={{
          padding: '10px 15px',
          backgroundColor: '#007bff',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer',
          fontSize: '1em',
          marginTop: '10px'
        }}
      >
        Submit
      </button>
    </form>
  );
}

export default MyForm;