useForm (original) (raw)

</> useForm: UseFormProps

useForm is a custom hook for managing forms with ease. It takes one object as optional argument. The following example demonstrates all of its properties along with their default values.

Generic props:

Option Description
mode Validation strategy before submitting behaviour.
reValidateMode Validation strategy after submitting behaviour.
defaultValues Default values for the form.
values Reactive values to update the form values.
errors Reactive errors to update the form errors.
resetOptions Option to reset form state update while updating new form values.
criteriaMode Display all validation errors or one at a time.
shouldFocusError Enable or disable built-in focus management.
delayError Delay error from appearing instantly.
shouldUseNativeValidation Use browser built-in form constraint API.
shouldUnregister Enable and disable input unregister after unmount.
disabled Disable the entire form with all associated inputs.

Schema validation props:

Option Description
resolver Integrates with your preferred schema validation library.
context A context object to supply for your schema validation.

Props


mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'


This option allows you to configure the validation strategy before a user submits the form. The validation occurs during the onSubmit event, which is triggered by invoking the handleSubmit function.

Name Type Description
onSubmit string Validation is triggered on the submit event, and inputs attach onChange event listeners to re-validate themselves.
onBlur string Validation is triggered on the blur event.
onChange string Validation is triggered on the changeevent for each input, leading to multiple re-renders. Warning: this often comes with a significant impact on performance.
onTouched string Validation is initially triggered on the first blur event. After that, it is triggered on every change event.Note: when using with Controller, make sure to wire up onBlur with the render prop.
all string Validation is triggered on both blur and change events.

reValidateMode: onChange | onBlur | onSubmit = 'onChange'


This option allows you to configure validation strategy when inputs with errors get re-validated after a user submits the form (onSubmit event and handleSubmit function executed). By default, re-validation occurs during the input change event.

defaultValues: FieldValues | () => Promise<FieldValues>


The defaultValues prop populates the entire form with default values. It supports both synchronous and asynchronous assignment of default values. While you can set an input's default value using defaultValue or defaultChecked (as detailed in the official React documentation), it is recommended to use defaultValues for the entire form.

useForm({

defaultValues: {

firstName: '',

lastName: ''

}

})

useForm({

defaultValues: async () => fetch('/api-endpoint');

})

RULES

values: FieldValues


The values prop will react to changes and update the form values, which is useful when your form needs to be updated by external state or server data. The values prop will overwrite the defaultValues prop, unless resetOptions: { keepDefaultValues: true } is also set for useForm.

function App({ values }) {

useForm({

values, 

})

}

function App() {

const values = useFetch("/api")

useForm({

defaultValues: {

  firstName: "",

  lastName: "",

},

values, 

})

}

errors: FieldErrors


The errors props will react to changes and update the server errors state, which is useful when your form needs to be updated by external server returned errors.

function App() {

const { errors, data } = useFetch("/api")

useForm({

errors, 

})

}

resetOptions: KeepStateOptions


This property is related to value update behaviors. When values or defaultValues are updated, the reset API is invoked internally. It's important to specify the desired behavior after values or defaultValues are asynchronously updated. The configuration option itself is a reference to the reset method's options.

useForm({ values })

useForm({ defaultValues: async () => await fetch() })

useForm({

values,

resetOptions: {

keepDirtyValues: true, 

keepErrors: true, 

},

})

context: object


This context object is mutable and will be injected into the resolver's second argument or Yup validation's context object. CodeSandbox

criteriaMode: firstError | all


When set to firstError (default), only the first error from each field will be gathered. When set to all, all errors from each field will be gathered. CodeSandbox

shouldFocusError: boolean = true


When set to true (default), and the user submits a form that fails validation, focus is set on the first field with an error.

NOTE

delayError: number


This configuration delays the display of error states to the end-user by a specified number of milliseconds. If the user corrects the error input, the error is removed instantly, and the delay is not applied. CodeSandbox

shouldUnregister: boolean = false


By default, an input value will be retained when input is removed. However, you can set shouldUnregister to true to unregister input during unmount.

shouldUseNativeValidation: boolean = false


This config will enable browser native validation. It will also enable CSS selectors :valid and:invalid making styling inputs easier. You can still use these selectors even when client-side validation is disabled.

Examples:


import { useForm } from "react-hook-form"

export default function App() {

const { register, handleSubmit } = useForm({

shouldUseNativeValidation: true,

})

const onSubmit = async (data) => {

console.log(data)

}

return (

<form onSubmit={handleSubmit(onSubmit)}>

  <input

    {...register("firstName", {

      required: "Please enter your first name.",

    })} 

  />

  <input type="submit" />

</form>

)

}

disabled: boolean = false


This config allows you to disable the entire form and all associated inputs when set to true.
This can be useful for preventing user interaction during asynchronous tasks or other situations where inputs should be temporarily unresponsive.

Examples:


import { useForm, Controller } from "react-hook-form"

const App = () => {

const [disabled, setDisabled] = useState(false)

const { register, handleSubmit, control } = useForm({

disabled,

})

return (

<form

  onSubmit={handleSubmit(async () => {

    setDisabled(true)

    await sleep(100)

    setDisabled(false)

  })}

>

  <input

    type={"checkbox"}

    {...register("checkbox")}

    data-testid={"checkbox"}

  />

  <select {...register("select")} data-testid={"select"} />

  <Controller

    control={control}

    render={({ field }) => <input disabled={field.disabled} />}

    name="test"

  />

  <button type="submit">Submit</button>

</form>

)

}

resolver: Resolver


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.

npm install @hookform/resolvers

Props

Name Type Description
values object This object contains the entire form values.
context object This is the context object which you can provide to the useForm config. It is a mutable object that can be changed on each re-render.
options { "criteriaMode": "string", "fields": "object", "names": "string[]" } This is the option object containing information about the validated fields, names and criteriaMode from useForm.

RULES

Examples:


import React from "react"

import { useForm } from "react-hook-form"

import { yupResolver } from "@hookform/resolvers/yup"

import * as yup from "yup"

type Inputs = {

name: string

age: string

}

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>

)

}

import { useForm } from "react-hook-form"

import { zodResolver } from "@hookform/resolvers/zod"

import * as z from "zod"

const schema = z.object({

name: z.string(),

age: z.number(),

})

type Schema = z.infer

const App = () => {

const { register, handleSubmit } = useForm({

resolver: zodResolver(schema),

})

const onSubmit = (data: Schema) => {

console.log(data)

}

return (

<form onSubmit={handleSubmit(onSubmit)}>

  <input {...register("name")} />

  <input {...register("age", { valueAsNumber: true })} type="number" />

  <input type="submit" />

</form>

)

}

import React from "react";

import { useForm } from "react-hook-form";

import { joiResolver } from "@hookform/resolvers/joi";

import Joi from "joi";

interface IFormInput {

name: string;

age: number;

}

const schema = Joi.object({

name: Joi.string().required(),

age: Joi.number().required()

});

const App = () => {

const { register, handleSubmit, formState: { errors } } = useForm({

resolver: joiResolver(schema)

});

const onSubmit = (data: IFormInput) => {

console.log(data);

};

return (

<form onSubmit={handleSubmit(onSubmit)}>

  <input {...register("name"} />

  <input type="number" {...register("age"} />

  <input type="submit" />

</form>

);

}

import { useForm } from "react-hook-form"

import { ajvResolver } from "@hookform/resolvers/ajv"

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 && <p>{errors.username.message}</p>}

  <input {...register("password")} />

  {errors.password && <p>{errors.password.message}</p>}

  <button type="submit">submit</button>

</form>

)

}

import * as React from "react"

import { useForm } from "react-hook-form"

import { vestResolver } from "@hookform/resolvers/vest"

import vest, { test, enforce } from "vest"

const validationSuite = vest.create((data = {}) => {

test("username", "Username is required", () => {

enforce(data.username).isNotEmpty()

})

test("username", "Must be longer than 3 chars", () => {

enforce(data.username).longerThan(3)

})

test("password", "Password is required", () => {

enforce(data.password).isNotEmpty()

})

test("password", "Password must be at least 5 chars", () => {

enforce(data.password).longerThanOrEquals(5)

})

test("password", "Password must contain a digit", () => {

enforce(data.password).matches(/[0-9]/)

})

test("password", "Password must contain a symbol", () => {

enforce(data.password).matches(/[^A-Za-z0-9]/)

})

})

const App = () => {

const { register, handleSubmit } = useForm({

resolver: vestResolver(validationSuite),

})

return (

<form onSubmit={handleSubmit((data) => console.log(data))}>

  <input {...register("username")} />

  <input {...register("password")} />

  <input type="submit" />

</form>

)

}

import * as React from "react"

import { useForm } from "react-hook-form"

import * as Joi from "joi"

interface IFormInputs {

username: string

}

const validationSchema = Joi.object({

username: Joi.string().alphanum().min(3).max(30).required(),

})

const App = () => {

const {

register,

handleSubmit,

formState: { errors },

} = useForm({

resolver: async (data) => {

  const { error, value: values } = validationSchema.validate(data, {

    abortEarly: false,

  })

  return {

    values: error ? {} : values,

    errors: error

      ? error.details.reduce((previous, currentError) => {

          return {

            ...previous,

            [currentError.path[0]]: currentError,

          }

        }, {})

      : {},

  }

},

})

const onSubmit = (data: IFormInputs) => console.log(data)

return (

<div className="App">

  <h1>resolver</h1>

  <form onSubmit={handleSubmit(onSubmit)}>

    <label>Username</label>

    <input {...register("username")} />

    {errors.username && <p>errors.username.message</p>}

    <input type="submit" />

  </form>

</div>

)

}

Need more? See Resolver Documentation

TIP

You can debug your schema via the following code snippet:

resolver: async (data, context, options) => {

console.log("formData", data)

console.log(

"validation result",

await anyResolver(schema)(data, context, options)

)

return anyResolver(schema)(data, context, options)

}

useForm return and useEffect dependencies

In a future major release, useForm return will be memoized to optimize performance and reflect changes in formState. As a result, adding the entire return value of useForm to a useEffect dependency list may lead to infinite loops.

WARNING

The following code is likely to create this situation:

const methods = useForm()

useEffect(() => {

methods.reset({ ... })

}, [methods])

Passing only the relevant methods, as showed below, should avoid this kind of issue:

const methods = useForm()

useEffect(() => {

methods.reset({ ... })

}, [methods.reset])

TIP

The recommended way is to pass destructured methods to the dependencies of an useEffect

const { reset } = useForm()

useEffect(() => {

reset({ ... })

}, [reset])

More info can be found on this issue

Return


The following list contains reference to useForm return props.

Thank you for your support

If you find React Hook Form to be useful in your project, please consider to star and support it.