
Security News
CISA Extends MITRE Contract as Crisis Accelerates Alternative CVE Coordination Efforts
CISA extended MITRE’s CVE contract by 11 months, avoiding a shutdown but leaving long-term governance and coordination issues unresolved.
@hookform/resolvers
Advanced tools
React Hook Form validation resolvers: Yup, Joi, Superstruct, Zod, Vest, Class Validator, io-ts, Nope, computed-types, TypeBox, arktype, Typanion, Effect-TS and VineJS
The @hookform/resolvers package is used in conjunction with React Hook Form to integrate external validation libraries. It provides resolvers that allow you to use your preferred validation schema with React Hook Form, ensuring that form data adheres to certain rules before it is processed or submitted.
Yup Resolver
Integrates Yup validation schema with React Hook Form.
{"import { yupResolver } from '@hookform/resolvers/yup';\nimport * as yup from 'yup';\n\nconst schema = yup.object().shape({\n name: yup.string().required(),\n age: yup.number().positive().integer().required(),\n});\n\nconst { register, handleSubmit, errors } = useForm({\n resolver: yupResolver(schema)\n});\n\n// In your form...\n<input name='name' ref={register} />\n<p>{errors.name?.message}</p>\n<input name='age' ref={register} />\n<p>{errors.age?.message}</p>"}
Joi Resolver
Integrates Joi validation schema with React Hook Form.
{"import { joiResolver } from '@hookform/resolvers/joi';\nimport Joi from 'joi';\n\nconst schema = Joi.object({\n username: Joi.string().alphanum().min(3).max(30).required(),\n password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')),\n});\n\nconst { register, handleSubmit, errors } = useForm({\n resolver: joiResolver(schema)\n});\n\n// In your form...\n<input name='username' ref={register} />\n<p>{errors.username?.message}</p>\n<input name='password' ref={register} />\n<p>{errors.password?.message}</p>"}
Zod Resolver
Integrates Zod validation schema with React Hook Form.
{"import { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\n\nconst schema = z.object({\n firstName: z.string().min(1, { message: 'First name is required' }),\n age: z.number().min(10, { message: 'Minimum age is 10' }),\n});\n\nconst { register, handleSubmit, errors } = useForm({\n resolver: zodResolver(schema)\n});\n\n// In your form...\n<input name='firstName' ref={register} />\n<p>{errors.firstName?.message}</p>\n<input name='age' ref={register} />\n<p>{errors.age?.message}</p>"}
React Hook Form is the core library that @hookform/resolvers is designed to work with. It provides a way to manage forms with minimal re-rendering, but it does not include built-in schema-based validation. @hookform/resolvers complements it by adding this capability.
Formik is another popular form management library for React. It handles form state, validation, and submission. Unlike React Hook Form, Formik includes built-in support for Yup validation without needing an additional resolver package.
Redux Form is a form library that works with Redux for state management. It includes validation functionalities but is generally considered heavier and more complex than React Hook Form and requires Redux to be part of the project.
Performant, flexible and extensible forms with easy to use validation.
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 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 | Infer values from schema | criteriaMode |
---|---|---|
AJV | ❌ | `firstError |
Arktype | ✅ | firstError |
class-validator | ✅ | `firstError |
computed-types | ✅ | firstError |
Effect | ✅ | `firstError |
fluentvalidation-ts | ❌ | firstError |
io-ts | ✅ | firstError |
joi | ❌ | `firstError |
Nope | ❌ | firstError |
Standard Schema | ✅ | `firstError |
Superstruct | ✅ | firstError |
typanion | ✅ | firstError |
typebox | ✅ | `firstError |
typeschema | ❌ | `firstError |
valibot | ✅ | `firstError |
vest | ❌ | `firstError |
vine | ✅ | `firstError |
yup | ✅ | `firstError |
zod | ✅ | `firstError |
Most of the resolvers can infer the output type from the schema. See comparison table for more details.
useForm<Input, Context, Output>()
Example:
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
id: z.number(),
});
// Automatically infers the output type from the schema
useForm({
resolver: zodResolver(schema),
});
// Force the output type
useForm<z.input<typeof schema>, any, z.output<typeof schema>>({
resolver: zodResolver(schema),
});
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 |
Dead simple Object schema validation.
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 (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
<input type="number" {...register('age')} />
<input type="submit" />
</form>
);
};
TypeScript-first schema validation with static type inference
⚠️ Example below uses the
valueAsNumber
, which requiresreact-hook-form
v6.12.0 (released Nov 28, 2020) or later.
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(1, { message: 'Required' }),
age: z.number().min(10),
});
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: zodResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
{errors.name?.message && <p>{errors.name?.message}</p>}
<input type="number" {...register('age', { valueAsNumber: true })} />
{errors.age?.message && <p>{errors.age?.message}</p>}
<input type="submit" />
</form>
);
};
A simple and composable way to validate data in JavaScript (or TypeScript).
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 (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
<input type="number" {...register('age', { valueAsNumber: true })} />
<input type="submit" />
</form>
);
};
The most powerful data validation library for JS.
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 (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
<input type="number" {...register('age')} />
<input type="submit" />
</form>
);
};
Vest 🦺 Declarative Validation Testing.
import { useForm } from 'react-hook-form';
import { vestResolver } from '@hookform/resolvers/vest';
import { create, test, enforce } from 'vest';
const validationSuite = create((data = {}) => {
test('username', 'Username is required', () => {
enforce(data.username).isNotEmpty();
});
test('password', 'Password is required', () => {
enforce(data.password).isNotEmpty();
});
});
const App = () => {
const { register, handleSubmit, errors } = useForm({
resolver: vestResolver(validationSuite),
});
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register('username')} />
<input type="password" {...register('password')} />
<input type="submit" />
</form>
);
};
Decorator-based property validation for classes.
⚠️ Remember to add these options to your
tsconfig.json
!
"strictPropertyInitialization": false,
"experimentalDecorators": true
import { useForm } from 'react-hook-form';
import { classValidatorResolver } from '@hookform/resolvers/class-validator';
import { Length, Min, IsEmail } from 'class-validator';
class User {
@Length(2, 30)
username: string;
@IsEmail()
email: string;
}
const resolver = classValidatorResolver(User);
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<User>({ resolver });
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input type="text" {...register('username')} />
{errors.username && <span>{errors.username.message}</span>}
<input type="text" {...register('email')} />
{errors.email && <span>{errors.email.message}</span>}
<input type="submit" value="Submit" />
</form>
);
};
Validate your data with powerful decoders.
import React from 'react';
import { useForm } from 'react-hook-form';
import { ioTsResolver } from '@hookform/resolvers/io-ts';
import t from 'io-ts';
// you don't have to use io-ts-types, but it's very useful
import tt from 'io-ts-types';
const schema = t.type({
username: t.string,
age: tt.NumberFromString,
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: ioTsResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
<input type="number" {...register('age')} />
<input type="submit" />
</form>
);
};
export default App;
A small, simple, and fast JS validator
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 (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
<input type="number" {...register('age')} />
<input type="submit" />
</form>
);
};
TypeScript-first schema validation with static type inference
import { useForm } from 'react-hook-form';
import { computedTypesResolver } from '@hookform/resolvers/computed-types';
import Schema, { number, string } from 'computed-types';
const schema = Schema({
username: string.min(1).error('username field is required'),
age: number,
});
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: computedTypesResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
{errors.name?.message && <p>{errors.name?.message}</p>}
<input type="number" {...register('age', { valueAsNumber: true })} />
{errors.age?.message && <p>{errors.age?.message}</p>}
<input type="submit" />
</form>
);
};
Static and runtime type assertion library with no dependencies
import { useForm } from 'react-hook-form';
import { typanionResolver } from '@hookform/resolvers/typanion';
import * as t from 'typanion';
const isUser = t.isObject({
username: t.applyCascade(t.isString(), [t.hasMinLength(1)]),
age: t.applyCascade(t.isNumber(), [
t.isInteger(),
t.isInInclusiveRange(1, 100),
]),
});
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: typanionResolver(isUser),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
{errors.name?.message && <p>{errors.name?.message}</p>}
<input type="number" {...register('age')} />
{errors.age?.message && <p>{errors.age?.message}</p>}
<input type="submit" />
</form>
);
};
The fastest JSON validator for Node.js and browser
import { useForm } from 'react-hook-form';
import { ajvResolver } from '@hookform/resolvers/ajv';
// must use `minLength: 1` to implement required field
const schema = {
type: 'object',
properties: {
username: {
type: 'string',
minLength: 1,
errorMessage: { minLength: 'username field is required' },
},
password: {
type: 'string',
minLength: 1,
errorMessage: { minLength: 'password field is required' },
},
},
required: ['username', 'password'],
additionalProperties: false,
};
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: ajvResolver(schema),
});
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register('username')} />
{errors.username && <span>{errors.username.message}</span>}
<input {...register('password')} />
{errors.password && <span>{errors.password.message}</span>}
<button type="submit">submit</button>
</form>
);
};
JSON Schema Type Builder with Static Type Resolution for TypeScript
ValueCheck
import { useForm } from 'react-hook-form';
import { typeboxResolver } from '@hookform/resolvers/typebox';
import { Type } from '@sinclair/typebox';
const schema = Type.Object({
username: Type.String({ minLength: 1 }),
password: Type.String({ minLength: 1 }),
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: typeboxResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
<input type="password" {...register('password')} />
<input type="submit" />
</form>
);
};
TypeCompiler
A high-performance JIT of TypeBox
, read more
import { useForm } from 'react-hook-form';
import { typeboxResolver } from '@hookform/resolvers/typebox';
import { Type } from '@sinclair/typebox';
import { TypeCompiler } from '@sinclair/typebox/compiler';
const schema = Type.Object({
username: Type.String({ minLength: 1 }),
password: Type.String({ minLength: 1 }),
});
const typecheck = TypeCompiler.Compile(schema);
const App = () => {
const { register, handleSubmit } = useForm({
resolver: typeboxResolver(typecheck),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
<input type="password" {...register('password')} />
<input type="submit" />
</form>
);
};
TypeScript's 1:1 validator, optimized from editor to runtime
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 (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
<input type="password" {...register('password')} />
<input type="submit" />
</form>
);
};
The modular and type safe schema library for validating structural data
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, 'Needs to be at least 3 characters'),
v.endsWith('cool', 'Needs to end with `cool`'),
),
password: v.string('password is required'),
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: valibotResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
<input type="password" {...register('password')} />
<input type="submit" />
</form>
);
};
Universal adapter for schema validation, compatible with any validation library
import { useForm } from 'react-hook-form';
import { typeschemaResolver } from '@hookform/resolvers/typeschema';
import { z } from 'zod';
// Use your favorite validation library
const schema = z.object({
username: z.string().min(1, { message: 'Required' }),
password: z.number().min(1, { message: 'Required' }),
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: typeschemaResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
<input type="password" {...register('password')} />
<input type="submit" />
</form>
);
};
A powerful TypeScript framework that provides a fully-fledged functional effect system with a rich standard library.
import React from 'react';
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 required' }),
),
password: Schema.String.pipe(
Schema.nonEmptyString({ message: () => 'password required' }),
),
});
type FormData = typeof schema.Type;
interface Props {
onSubmit: (data: FormData) => void;
}
function TestComponent({ onSubmit }: Props) {
const {
register,
handleSubmit,
formState: { errors },
// provide generic if TS has issues inferring types
} = useForm<FormData>({
resolver: effectTsResolver(schema),
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('username')} />
{errors.username && <span role="alert">{errors.username.message}</span>}
<input {...register('password')} />
{errors.password && <span role="alert">{errors.password.message}</span>}
<button type="submit">submit</button>
</form>
);
}
VineJS is a form data validation library for Node.js
import { useForm } from 'react-hook-form';
import { vineResolver } from '@hookform/resolvers/vine';
import vine from '@vinejs/vine';
const schema = vine.compile(
vine.object({
username: vine.string().minLength(1),
password: vine.string().minLength(1),
}),
);
const App = () => {
const { register, handleSubmit } = useForm({
resolver: vineResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
{errors.username && <span role="alert">{errors.username.message}</span>}
<input {...register('password')} />
{errors.password && <span role="alert">{errors.password.message}</span>}
<button type="submit">submit</button>
</form>
);
};
A TypeScript-first library for building strongly-typed validation rules
import { useForm } from 'react-hook-form';
import { fluentValidationResolver } from '@hookform/resolvers/fluentvalidation-ts';
import { Validator } from 'fluentvalidation-ts';
class FormDataValidator extends Validator<FormData> {
constructor() {
super();
this.ruleFor('username')
.notEmpty()
.withMessage('username is a required field');
this.ruleFor('password')
.notEmpty()
.withMessage('password is a required field');
}
}
const App = () => {
const { register, handleSubmit } = useForm({
resolver: fluentValidationResolver(new FormDataValidator()),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
{errors.username && <span role="alert">{errors.username.message}</span>}
<input {...register('password')} />
{errors.password && <span role="alert">{errors.password.message}</span>}
<button type="submit">submit</button>
</form>
);
};
A standard interface for TypeScript schema validation libraries
Example zod
import { useForm } from 'react-hook-form';
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(1, { message: 'Required' }),
age: z.number().min(10),
});
const App = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: standardSchemaResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
{errors.name?.message && <p>{errors.name?.message}</p>}
<input type="number" {...register('age', { valueAsNumber: true })} />
{errors.age?.message && <p>{errors.age?.message}</p>}
<input type="submit" />
</form>
);
};
Example arkType
import { useForm } from 'react-hook-form';
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema';
import { type } from 'arktype';
const schema = type({
username: 'string>1',
password: 'string>1',
});
const App = () => {
const { register, handleSubmit } = useForm({
resolver: standardSchemaResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('username')} />
<input type="password" {...register('password')} />
<input type="submit" />
</form>
);
};
Thanks go to all our backers! [Become a backer].
Thanks go to these wonderful people! [Become a contributor].
FAQs
React Hook Form validation resolvers: Yup, Joi, Superstruct, Zod, Vest, Class Validator, io-ts, Nope, computed-types, TypeBox, arktype, Typanion, Effect-TS and VineJS
The npm package @hookform/resolvers receives a total of 0 weekly downloads. As such, @hookform/resolvers popularity was classified as not popular.
We found that @hookform/resolvers demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
CISA extended MITRE’s CVE contract by 11 months, avoiding a shutdown but leaving long-term governance and coordination issues unresolved.
Product
Socket's Rubygems ecosystem support is moving from beta to GA, featuring enhanced security scanning to detect supply chain threats beyond traditional CVEs in your Ruby dependencies.
Research
The Socket Research Team investigates a malicious npm package that appears to be an Advcash integration but triggers a reverse shell during payment success, targeting servers handling transactions.