验证解析器: Yup、Zod、Superstruct、Joi、Vest、Class Validator、io-ts、Nope、computed-types、typanion、Ajv、TypeBox、ArkType、Valibot、effect-ts、Vi
Performant, flexible and extensible forms with easy to use validation.
## React Hook Form Resolvers
This function allows you to use any external validation library such as Yup, Zod, Joi, Vest, Ajv and many others. The goal is to make sure you can seamlessly integrate whichever validation library you prefer. If you're not using a library, you can always write your own logic to validate your forms.
## Install
Install your preferred validation library alongside `@hookform/resolvers`.
npm install @hookform/resolvers # npm
yarn add @hookform/resolvers # yarn
pnpm install @hookform/resolvers # pnpm
bun install @hookform/resolvers # bun
Resolver Comparison
| resolver | Infer values
from schema | [criteriaMode](https://react-hook-form.com/docs/useform#criteriaMode) |
| -------------------- | -------------------------------- | ----------------------------------------------------------------------- |
| AJV | ❌ | `firstError \| all` |
| ata-validator | ❌ | `firstError \| all` |
| Arktype | ✅ | `firstError` |
| class-validator | ✅ | `firstError \| all` |
| computed-types | ✅ | `firstError` |
| Effect | ✅ | `firstError \| all` |
| fluentvalidation-ts | ❌ | `firstError` |
| io-ts | ✅ | `firstError` |
| joi | ❌ | `firstError \| all` |
| Nope | ❌ | `firstError` |
| Standard Schema | ✅ | `firstError \| all` |
| Superstruct | ✅ | `firstError` |
| typanion | ✅ | `firstError` |
| typebox | ✅ | `firstError \| all` |
| typeschema | ❌ | `firstError \| all` |
| valibot | ✅ | `firstError \| all` |
| vest | ❌ | `firstError \| all` |
| vine | ✅ | `firstError \| all` |
| yup | ✅ | `firstError \| all` |
| zod | ✅ | `firstError \| all` |
## TypeScript
Most of the resolvers can infer the output type from the schema. See comparison table for more details.
```tsx
useForm()
```
Example:
```tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod'; // or 'zod/v4'
const schema = z.object({
id: z.number(),
});
// Automatically infers the output type from the schema
useForm({
resolver: zodResolver(schema),
});
// Force the output type
useForm, any, z.output>({
resolver: zodResolver(schema),
});
```
## Links
- [React-hook-form validation resolver documentation](https://react-hook-form.com/docs/useform#resolver)
### Table of Contents
- [Install](#install)
- [TypeScript](#typescript)
- [Links](#links)
- [Table of Contents](#table-of-contents)
- [API](#api)
- [Quickstart](#quickstart)
- [Yup](#yup)
- [Zod](#zod)
- [Superstruct](#superstruct)
- [Joi](#joi)
- [Vest](#vest)
- [Class Validator](#class-validator)
- [io-ts](#io-ts)
- [Nope](#nope)
- [computed-types](#computed-types)
- [typanion](#typanion)
- [Ajv](#ajv)
- [TypeBox](#typebox)
- [With `ValueCheck`](#with-valuecheck)
- [With `TypeCompiler`](#with-typecompiler)
- [Custom/third-party types](#customthird-party-types-eg-elysiajss-tfiles)
- [ArkType](#arktype)
- [Valibot](#valibot)
- [TypeSchema](#typeschema)
- [effect-ts](#effect-ts)
- [VineJS](#vinejs)
- [fluentvalidation-ts](#fluentvalidation-ts)
- [standard-schema](#standard-schema)
- [ata-validator](#ata-validator)
- [Backers](#backers)
- [Contributors](#contributors)
## API
```
type Options = {
mode: 'async' | 'sync',
raw?: boolean
}
resolver(schema: object, schemaOptions?: object, resolverOptions: Options)
```
| | type | Required | Description |
| --------------- | -------- | -------- | --------------------------------------------- |
| schema | `object` | ✓ | validation schema |
| schemaOptions | `object` | | validation library schema options |
| resolverOptions | `object` | | resolver options, `async` is the default mode |
## Quickstart
### [Yup](https://github.com/jquense/yup)
Dead simple Object schema validation.
> ⚠️ Pass context via `useForm({ context })`, not via `yupResolver`'s `schemaOptions`. `schemaOptions.context` is overridden by the form context, so use the `useForm` context object instead.
```tsx
// Correct
useForm({
resolver: yupResolver(schema),
context: { foo: true },
});
// Avoid - schemaOptions.context will be ignored/overridden
yupResolver(schema, { context: { foo: true } });
```
```tsx
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
const schema = yup
.object()
.shape({
name: yup.string().required(),
age: yup.number().required(),
})
.required();
const App = () => {
const { register, handleSubmit } = useForm({
resolver: yupResolver(schema),
});
return (
console.log(d))}>
);
};
```
### [Zod](https://github.com/colinhacks/zod)
TypeScript-first schema validation with static type inference
> ⚠️ Example below uses the `valueAsNumber`, which requires `react-hook-form` v6.12.0 (released Nov 28, 2020) or later.
```
…
```
> ⚠️ If your schema uses `.default(...)` on a field, that field becomes optional on the schema's _input_ type (`z.input`) but stays required on its _output_ type (`z.output`/`z.infer`) — the default only fills it in after validation. Passing a single generic to `useForm` pins both to the same type and will conflict with `zodResolver`, which infers input and output separately. Either omit the generic and let it infer from `resolver`, or specify all three explicitly:
>
> ```tsx
> const schema = z.object({ debug_mode: z.boolean().default(true) });
>
> useForm, unknown, z.output>({
> resolver: zodResolver(schema),
> });
> ```
### [Superstruct](https://github.com/ianstormtaylor/superstruct)
A simple and composable way to validate data in JavaScript (or TypeScript).
```tsx
import { useForm } from 'react-hook-form';
import { superstructResolver } from '@hookform/resolvers/superstruct';
import { object, string, number } from 'superstruct';
const schema = object({
name: string(),
age: number(),
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: superstructResolver(schema),
});
return (
console.log(d))}>
);
};
```
### [Joi](https://github.com/sideway/joi)
The most powerful data validation library for JS.
```tsx
import { useForm } from 'react-hook-form';
import { joiResolver } from '@hookform/resolvers/joi';
import Joi from 'joi';
const schema = Joi.object({
name: Joi.string().required(),
age: Joi.number().required(),
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: joiResolver(schema),
});
return (
console.log(d))}>
);
};
```
### [Vest](https://github.com/ealush/vest)
Vest Declarative Validation Testing.
```
…
```
### [Class Validator](https://github.com/typestack/class-validator)
Decorator-based property validation for classes.
> ⚠️ Remember to add these options to your `tsconfig.json`!
```
"strictPropertyInitialization": false,
"experimentalDecorators": true
```
```
…
```
### [io-ts](https://github.com/gcanti/io-ts)
Validate your data with powerful decoders.
```
…
```
### [Nope](https://github.com/bvego/nope-validator)
A small, simple, and fast JS validator
```tsx
import { useForm } from 'react-hook-form';
import { nopeResolver } from '@hookform/resolvers/nope';
import Nope from 'nope-validator';
const schema = Nope.object().shape({
name: Nope.string().required(),
age: Nope.number().required(),
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: nopeResolver(schema),
});
return (
console.log(d))}>
);
};
```
### [computed-types](https://github.com/neuledge/computed-types)
TypeScript-first schema validation with static type inference
```
…
```
### [typanion](https://github.com/arcanis/typanion)
Static and runtime type assertion library with no dependencies
```
…
```
### [Ajv](https://github.com/ajv-validator/ajv)
The fastest JSON validator for Node.js and browser
```
…
```
### [TypeBox](https://github.com/sinclairzx81/typebox)
JSON Schema Type Builder with Static Type Resolution for TypeScript
#### With `ValueCheck`
```
…
```
#### With `TypeCompiler`
A high-performance JIT of `TypeBox`, [read more](https://github.com/sinclairzx81/typebox#typecompiler)
```
…
```
#### Custom/third-party types (e.g. ElysiaJS's `t.Files()`)
`typeboxResolver` validates using `@sinclair/typebox`'s own `Value.Errors`/`Value.Check`, so any schema
`Kind` not built into TypeBox (custom types, or ones defined by a third-party library such as ElysiaJS)
must be registered with TypeBox's own `TypeRegistry` (and `FormatRegistry` for string formats) before
it's used — this is a TypeBox-level extension point, not something `@hookform/resolvers` wraps or needs
to expose separately:
```tsx
import { TypeRegistry } from '@sinclair/typebox';
if (!TypeRegistry.Has('Files')) {
TypeRegistry.Set('Files', (schema, value) => Array.isArray(value));
}
```
Make sure this registration runs against the same `@sinclair/typebox` module instance the schema was
built with — if a library vendors its own copy of `@sinclair/typebox` instead of relying on the shared
peer dependency, its registrations won't be visible here, and you'll see a runtime `"Unknown type"` error.
### [ArkType](https://github.com/arktypeio/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>1',
password: 'string>1',
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: arktypeResolver(schema),
});
return (
console.log(d))}>
);
};
```
### [Valibot](https://github.com/fabian-hiller/valibot)
The modular and type safe schema library for validating structural data
```
…
```
> ⚠️ If your schema uses `v.transform(...)` (or `v.pipe(..., v.transform(...))`) on a field, that field's
> parsed _output_ type can differ from what the user actually types (its _input_ type) — e.g. a string
> input transformed into a number. Passing a single generic to `useForm` pins both the submitted values
> and the `handleSubmit` payload to that one type, which conflicts with `valibotResolver`, since it infers
> input and output separately. Either omit the generic and let it infer from `resolver`, or specify all
> three explicitly:
>
> ```tsx
> const schema = v.object({
> name: v.string(),
> number: v.pipe(v.string(), v.transform(Number)),
> });
>
> useForm, unknown, v.InferOutput>({
> reso