Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
React Hook Form Resolvers
https://github.com/react-hook-form/resolvers
Admin
React Hook Form Resolvers provide an adapter to integrate popular external validation libraries such
...
Tokens:
10,216
Snippets:
45
Trust Score:
9.1
Update:
1 day ago
Context
Skills
Chat
Benchmark
75
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# @hookform/resolvers React Hook Form Resolvers is a library that provides validation resolver adapters for React Hook Form. It enables seamless integration with popular validation libraries including Zod, Yup, Joi, Vest, Valibot, Ajv, class-validator, io-ts, TypeBox, ArkType, Effect-TS, VineJS, and more. Each resolver transforms validation library errors into the format expected by React Hook Form. The library follows a consistent API pattern across all resolvers: you pass a validation schema to the resolver function, which returns a resolver compatible with React Hook Form's `useForm` hook. Resolvers support both synchronous and asynchronous validation modes, native HTML5 validation, and the ability to return either parsed/transformed values or raw input values. ## zodResolver Creates a resolver for react-hook-form using Zod schema validation. Supports both Zod v3 and v4, automatically detecting the schema version. Provides full TypeScript inference of input and output types. ```tsx import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; // or 'zod/v4' const schema = z.object({ name: z.string().min(1, { message: 'Name is required' }), email: z.string().email({ message: 'Invalid email address' }), age: z.number().min(18, { message: 'Must be at least 18' }), }); type FormData = z.infer<typeof schema>; function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: zodResolver(schema), // Optional: use sync mode for faster validation // resolver: zodResolver(schema, undefined, { mode: 'sync' }), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('name')} /> {errors.name && <span>{errors.name.message}</span>} <input {...register('email')} /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age', { valueAsNumber: true })} /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## yupResolver Creates a resolver for react-hook-form using Yup schema validation. Supports schema options and context passing from useForm. ```tsx import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from 'yup'; const schema = yup.object({ username: yup.string().required('Username is required').min(3, 'Min 3 characters'), password: yup.string().required('Password is required').min(8, 'Min 8 characters'), confirmPassword: yup .string() .oneOf([yup.ref('password')], 'Passwords must match') .required('Please confirm your password'), }).required(); type FormData = yup.InferType<typeof schema>; function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: yupResolver(schema, { abortEarly: false, // Validate all fields, not just first error }), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input type="password" {...register('password')} placeholder="Password" /> {errors.password && <span>{errors.password.message}</span>} <input type="password" {...register('confirmPassword')} placeholder="Confirm Password" /> {errors.confirmPassword && <span>{errors.confirmPassword.message}</span>} <button type="submit">Register</button> </form> ); } ``` ## joiResolver Creates a resolver for react-hook-form using Joi schema validation. Supports async validation and context passing. ```tsx import { useForm } from 'react-hook-form'; import { joiResolver } from '@hookform/resolvers/joi'; import Joi from 'joi'; const schema = Joi.object({ firstName: Joi.string().required().messages({ 'string.empty': 'First name is required', }), lastName: Joi.string().required().messages({ 'string.empty': 'Last name is required', }), email: Joi.string() .email({ tlds: { allow: false } }) .required() .messages({ 'string.email': 'Invalid email format', 'string.empty': 'Email is required', }), age: Joi.number().min(0).max(120).required(), }); interface FormData { firstName: string; lastName: string; email: string; age: number; } function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: joiResolver(schema, { abortEarly: false, }), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('firstName')} /> {errors.firstName && <span>{errors.firstName.message}</span>} <input {...register('lastName')} /> {errors.lastName && <span>{errors.lastName.message}</span>} <input {...register('email')} /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age')} /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## vestResolver Creates a resolver for react-hook-form using Vest declarative validation testing. Supports field-level validation and async rules. ```tsx import { useForm } from 'react-hook-form'; import { vestResolver } from '@hookform/resolvers/vest'; import { create, test, enforce } from 'vest'; interface FormData { username: string; email: string; password: string; } const validationSuite = create((data: FormData = {} as FormData) => { test('username', 'Username is required', () => { enforce(data.username).isNotBlank(); }); test('username', 'Username must be at least 3 characters', () => { enforce(data.username).longerThanOrEquals(3); }); test('email', 'Email is required', () => { enforce(data.email).isNotBlank(); }); test('email', 'Please enter a valid email', () => { enforce(data.email).matches(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); }); test('password', 'Password is required', () => { enforce(data.password).isNotBlank(); }); test('password', 'Password must be at least 8 characters', () => { enforce(data.password).longerThanOrEquals(8); }); }); function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: vestResolver(validationSuite), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input {...register('email')} placeholder="Email" /> {errors.email && <span>{errors.email.message}</span>} <input type="password" {...register('password')} placeholder="Password" /> {errors.password && <span>{errors.password.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## valibotResolver Creates a resolver for react-hook-form using Valibot schema validation. Valibot is a modular and type-safe schema library with a small bundle size. ```tsx import { useForm } from 'react-hook-form'; import { valibotResolver } from '@hookform/resolvers/valibot'; import * as v from 'valibot'; const schema = v.object({ username: v.pipe( v.string('Username is required'), v.minLength(3, 'Username must be at least 3 characters'), v.maxLength(20, 'Username must be at most 20 characters'), ), email: v.pipe( v.string('Email is required'), v.email('Please enter a valid email'), ), age: v.pipe( v.number('Age must be a number'), v.minValue(18, 'Must be at least 18 years old'), ), }); type FormData = v.InferOutput<typeof schema>; function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: valibotResolver(schema), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input {...register('email')} placeholder="Email" /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age', { valueAsNumber: true })} placeholder="Age" /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## ajvResolver Creates a resolver for react-hook-form using Ajv JSON Schema validation. Supports custom error messages via ajv-errors plugin. ```tsx import { useForm } from 'react-hook-form'; import { ajvResolver } from '@hookform/resolvers/ajv'; const schema = { type: 'object', properties: { username: { type: 'string', minLength: 3, maxLength: 20, errorMessage: { minLength: 'Username must be at least 3 characters', maxLength: 'Username must be at most 20 characters', }, }, email: { type: 'string', format: 'email', errorMessage: { format: 'Please enter a valid email address', }, }, age: { type: 'integer', minimum: 18, errorMessage: { minimum: 'Must be at least 18 years old', }, }, }, required: ['username', 'email', 'age'], additionalProperties: false, errorMessage: { required: { username: 'Username is required', email: 'Email is required', age: 'Age is required', }, }, } as const; interface FormData { username: string; email: string; age: number; } function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: ajvResolver(schema), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input {...register('email')} placeholder="Email" /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age')} placeholder="Age" /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## classValidatorResolver Creates a resolver for react-hook-form using class-validator decorator-based validation. Requires TypeScript with experimental decorators enabled. ```tsx import { useForm } from 'react-hook-form'; import { classValidatorResolver } from '@hookform/resolvers/class-validator'; import { IsEmail, IsNotEmpty, Length, Min, IsInt } from 'class-validator'; class UserFormSchema { @IsNotEmpty({ message: 'Username is required' }) @Length(3, 20, { message: 'Username must be between 3 and 20 characters' }) username: string; @IsNotEmpty({ message: 'Email is required' }) @IsEmail({}, { message: 'Please enter a valid email' }) email: string; @IsInt({ message: 'Age must be an integer' }) @Min(18, { message: 'Must be at least 18 years old' }) age: number; } function App() { const { register, handleSubmit, formState: { errors }, } = useForm<UserFormSchema>({ resolver: classValidatorResolver(UserFormSchema), }); const onSubmit = (data: UserFormSchema) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input {...register('email')} placeholder="Email" /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age', { valueAsNumber: true })} placeholder="Age" /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## typeboxResolver Creates a resolver for react-hook-form using TypeBox JSON Schema type builder with static type resolution. ```tsx import { useForm } from 'react-hook-form'; import { typeboxResolver } from '@hookform/resolvers/typebox'; import { Type, Static } from '@sinclair/typebox'; const schema = Type.Object({ username: Type.String({ minLength: 3, maxLength: 20 }), email: Type.String({ format: 'email' }), age: Type.Integer({ minimum: 18 }), }); type FormData = Static<typeof schema>; function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: typeboxResolver(schema), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input {...register('email')} placeholder="Email" /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age', { valueAsNumber: true })} placeholder="Age" /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## effectTsResolver Creates a resolver for react-hook-form using Effect-TS Schema validation with full functional effect system support. ```tsx import { useForm } from 'react-hook-form'; import { effectTsResolver } from '@hookform/resolvers/effect-ts'; import { Schema } from 'effect'; const schema = Schema.Struct({ username: Schema.String.pipe( Schema.nonEmptyString({ message: () => 'Username is required' }), Schema.minLength(3, { message: () => 'Username must be at least 3 characters' }), ), email: Schema.String.pipe( Schema.nonEmptyString({ message: () => 'Email is required' }), ), age: Schema.Number.pipe( Schema.greaterThanOrEqualTo(18, { message: () => 'Must be at least 18 years old' }), ), }); type FormData = typeof schema.Type; function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: effectTsResolver(schema), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input {...register('email')} placeholder="Email" /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age', { valueAsNumber: true })} placeholder="Age" /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## standardSchemaResolver Creates a universal resolver for react-hook-form that works with any validation library implementing the Standard Schema interface. ```tsx import { useForm } from 'react-hook-form'; import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'; import { z } from 'zod'; // Or use any Standard Schema compatible library: Valibot, ArkType, etc. const schema = z.object({ username: z.string().min(3, 'Username must be at least 3 characters'), email: z.string().email('Please enter a valid email'), age: z.number().min(18, 'Must be at least 18 years old'), }); type FormData = z.infer<typeof schema>; function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: standardSchemaResolver(schema), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input {...register('email')} placeholder="Email" /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age', { valueAsNumber: true })} placeholder="Age" /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## arktypeResolver Creates a resolver for react-hook-form using ArkType, TypeScript's 1:1 validator optimized from editor to runtime. ```tsx import { useForm } from 'react-hook-form'; import { arktypeResolver } from '@hookform/resolvers/arktype'; import { type } from 'arktype'; const schema = type({ username: 'string>2', // string with length > 2 email: 'email', age: 'integer>=18', }); type FormData = typeof schema.infer; function App() { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: arktypeResolver(schema), }); const onSubmit = (data: FormData) => { console.log('Valid data:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('username')} placeholder="Username" /> {errors.username && <span>{errors.username.message}</span>} <input {...register('email')} placeholder="Email" /> {errors.email && <span>{errors.email.message}</span>} <input type="number" {...register('age', { valueAsNumber: true })} placeholder="Age" /> {errors.age && <span>{errors.age.message}</span>} <button type="submit">Submit</button> </form> ); } ``` ## Resolver Options All resolvers support common options for customizing validation behavior. The `mode` option controls sync/async validation, and the `raw` option determines whether to return parsed values or raw input. ```tsx import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; const schema = z.object({ price: z.string().transform((val) => parseFloat(val)), }); // Async validation (default) - returns transformed values useForm({ resolver: zodResolver(schema), }); // Sync validation - faster but no async validations useForm({ resolver: zodResolver(schema, undefined, { mode: 'sync' }), }); // Raw mode - returns original input values, not transformed useForm({ resolver: zodResolver(schema, undefined, { raw: true }), }); // Combined options useForm({ resolver: zodResolver(schema, undefined, { mode: 'sync', raw: true }), }); // Using criteriaMode to get all errors for a field useForm({ resolver: zodResolver(schema), criteriaMode: 'all', // Returns all validation errors, not just first }); ``` ## Summary React Hook Form Resolvers provides a unified integration layer between React Hook Form and the most popular JavaScript/TypeScript validation libraries. The primary use cases include form validation in React applications where type safety and developer experience are priorities, migrating existing validation logic to React Hook Form, and building form-heavy applications that require consistent validation patterns across different data models. Integration follows a straightforward pattern: install the resolvers package alongside your preferred validation library, import the specific resolver function, create your validation schema using the library's syntax, and pass the resolver to useForm's resolver option. All resolvers support TypeScript type inference, enabling autocomplete and type checking for form values. The library handles error transformation, field path mapping, and native HTML5 validation integration automatically, making it easy to switch between validation libraries or use multiple libraries in the same project.