Skip to main content
Glama
react-hook-form.txt•8.29 kB
# React Hook Form **Performant, flexible, and extensible forms with easy-to-use validation** React Hook Form is a performance-oriented form validation library for React applications, providing a set of hooks for efficient form management and re-render optimization. ## Installation ```bash npm install react-hook-form ``` ## Core Concepts ### useForm Hook The `useForm` hook is the primary way to manage form state and validation. It returns methods for registering inputs, handling submission, and accessing form state. ```jsx import { useForm } from 'react-hook-form'; function App() { const { register, handleSubmit, formState: { errors }, } = useForm(); const onSubmit = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('firstName')} /> <input {...register('lastName', { required: true })} /> {errors.lastName && <p>Last name is required.</p>} <input {...register('age', { pattern: /\d+/ })} /> {errors.age && <p>Please enter number for age.</p>} <input type="submit" /> </form> ); } ``` ## Basic Usage ### Registering Inputs Use the `register` function to connect inputs to the form state: ```jsx <input {...register('fieldName')} /> // With validation <input {...register('email', { required: 'Email is required', pattern: { value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, message: 'Invalid email address' } })} /> ``` ### Validation Rules Common validation options: - `required`: boolean or error message - `pattern`: regex pattern with optional message - `minLength` / `maxLength`: length constraints - `min` / `max`: value constraints - `validate`: custom validation function ```jsx <input {...register('username', { required: 'Username is required', minLength: { value: 3, message: 'Username must be at least 3 characters' }, validate: async (value) => { const available = await checkAvailability(value); return available || 'Username is taken'; } })} /> ``` ## Controller Component For integrating controlled components (Material-UI, React-Select, etc.): ```jsx import { useForm, Controller } from 'react-hook-form'; import Select from 'react-select'; function App() { const { handleSubmit, control } = useForm(); const options = [ { value: 'chocolate', label: 'Chocolate' }, { value: 'strawberry', label: 'Strawberry' }, { value: 'vanilla', label: 'Vanilla' } ]; const onSubmit = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="selectField" control={control} render={({ field }) => ( <Select {...field} options={options} /> )} /> <button type="submit">Submit</button> </form> ); } ``` ## FormProvider For deeply nested forms, use FormProvider to access form context: ```jsx import { useForm, FormProvider, useFormContext } from 'react-hook-form'; function NestedInput() { const { register } = useFormContext(); return <input {...register('test')} />; } function App() { const methods = useForm(); return ( <FormProvider {...methods}> <form onSubmit={methods.handleSubmit(onSubmit)}> <NestedInput /> <button type="submit">Submit</button> </form> </FormProvider> ); } ``` ## Integration with Schema Validators ### Zod Integration ```jsx import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; const schema = z.object({ firstName: z.string().min(1, 'First name is required'), lastName: z.string().min(1, 'Last name is required'), age: z.number().min(18, 'Must be 18 or older') }); function App() { const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver(schema) }); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('firstName')} /> {errors.firstName && <p>{errors.firstName.message}</p>} <input {...register('lastName')} /> {errors.lastName && <p>{errors.lastName.message}</p>} <input type="number" {...register('age', { valueAsNumber: true })} /> {errors.age && <p>{errors.age.message}</p>} <button type="submit">Submit</button> </form> ); } ``` ## useForm Options Key configuration options: ```typescript const { register, handleSubmit } = useForm({ mode: 'onChange', // When to validate (onChange, onBlur, onSubmit, onTouched, all) reValidateMode: 'onChange', // When to re-validate defaultValues: {}, // Default form values resolver: zodResolver(schema), // External validation schema shouldFocusError: true, // Auto-focus on first error shouldUnregister: false, // Keep values after unmount delayError: 0, // Delay error display (ms) }); ``` ## Watching Values Monitor specific form fields: ```jsx const { register, watch } = useForm(); // Watch single field const firstName = watch('firstName'); // Watch multiple fields const { firstName, lastName } = watch(['firstName', 'lastName']); // Watch all fields const allValues = watch(); ``` ## Form State Access form state information: ```jsx const { formState } = useForm(); const { isDirty, // Form has been modified dirtyFields, // Object of modified fields touchedFields,// Object of touched fields isSubmitted, // Form has been submitted isSubmitting, // Form is currently submitting isValid, // Form is valid isValidating, // Form is validating errors, // Validation errors } = formState; ``` ## Error Handling ```jsx const { register, handleSubmit, setError, clearErrors, formState: { errors } } = useForm(); // Manual error setting setError('username', { type: 'manual', message: 'Username is already taken' }); // Clear specific error clearErrors('username'); // Clear all errors clearErrors(); ``` ## Best Practices 1. **Use uncontrolled components** when possible for better performance 2. **Leverage resolvers** (Zod, Yup) for complex validation 3. **Memoize validation functions** to avoid re-creating them 4. **Use Controller** only when necessary (for third-party UI libraries) 5. **Avoid unnecessary re-renders** by using watch() sparingly 6. **Set defaultValues** to avoid undefined controlled component warnings ## Performance Tips - React Hook Form minimizes re-renders by isolating component updates - Only subscribed components re-render on value changes - Use `useWatch` for granular subscriptions instead of `watch()` - Disable native validation with `noValidate` on form element ## Common Patterns ### Dynamic Fields ```jsx import { useFieldArray } from 'react-hook-form'; function DynamicForm() { const { control, register } = useForm(); const { fields, append, remove } = useFieldArray({ control, name: 'items' }); return ( <> {fields.map((field, index) => ( <div key={field.id}> <input {...register(`items.${index}.name`)} /> <button onClick={() => remove(index)}>Remove</button> </div> ))} <button onClick={() => append({ name: '' })}>Add</button> </> ); } ``` ### Async Validation ```jsx <input {...register('username', { validate: async (value) => { const response = await fetch(`/api/check-username/${value}`); const isAvailable = await response.json(); return isAvailable || 'Username is taken'; } })} /> ``` ### Conditional Validation ```jsx const { register, watch } = useForm(); const country = watch('country'); <input {...register('zipCode', { required: country === 'US', pattern: country === 'US' ? /^\d{5}$/ : undefined })} /> ``` ## TypeScript Support React Hook Form has excellent TypeScript support: ```typescript type FormData = { firstName: string; lastName: string; age: number; }; const { register, handleSubmit } = useForm<FormData>(); const onSubmit = (data: FormData) => { // data is fully typed console.log(data.firstName); }; ``` ## Resources - Official Docs: https://react-hook-form.com/ - GitHub: https://github.com/react-hook-form/react-hook-form - Resolver Libraries: @hookform/resolvers (Zod, Yup, Joi support)

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CaullenOmdahl/Nextjs-React-Tailwind-Assistant'

If you have feedback or need assistance with the MCP directory API, please join our Discord server