trigger
Manually trigger validation without submitting.
</> trigger: UseFormTrigger
Manually triggers form or input validation. This method is also useful when you have dependent validation (input validation depends on another input's value). trigger returns Promise<boolean>, resolving true when the targeted field(s) pass validation and false otherwise.
Props
| Name | Type | Description | Example |
|---|---|---|---|
| name | undefined | Triggers validation on all fields. | trigger() |
| string | Triggers validation on a specific field value by name | trigger("yourDetails.firstName") | |
| string[] | Triggers validation on multiple fields by name. | trigger(["yourDetails.lastName"]) | |
| shouldFocus | boolean | Since v7.7.0 Focuses the input when an error is set. This only works when the input's reference is registered, it will not work for custom register as well. | trigger('name', { shouldFocus: true }) |
| shouldTouch | boolean | Since v7.87.0 Marks the targeted field(s) as touched, regardless of the validation result. Useful for validating and touching a field (or the whole form) without reaching for setValue's shouldTouch option as a workaround. | trigger('name', { shouldTouch: true }) |
Render-optimization isolation only applies when you target a single field by passing a string name. Passing an array of names, or calling trigger() with no arguments, re-renders the entire form state.
Examples
import { useState } from "react"import { useForm } from "react-hook-form"type FormInputs = {firstName: stringlastName: string}export default function App() {const {register,trigger,formState: { errors },} = useForm<FormInputs>({defaultValues: { firstName: "", lastName: "" },})const [status, setStatus] = useState("")const check = async (names?: keyof FormInputs | (keyof FormInputs)[]) => {const isValid = await trigger(names, { shouldFocus: true })setStatus(isValid ? "All checked fields are valid" : "Fix the errors above")}return (<form><input{...register("firstName", { required: "First name is required" })}placeholder="First name"/>{errors.firstName && <p role="alert">{errors.firstName.message}</p>}<input{...register("lastName", { required: "Last name is required" })}placeholder="Last name"/>{errors.lastName && <p role="alert">{errors.lastName.message}</p>}<button type="button" onClick={() => check("lastName")}>Trigger</button><button type="button" onClick={() => check(["firstName", "lastName"])}>Trigger Multiple</button><button type="button" onClick={() => check()}>Trigger All</button><p>{status}</p></form>)}
import { useState } from "react"import { useForm } from "react-hook-form"export default function App() {const {register,trigger,formState: { errors },} = useForm({defaultValues: { firstName: "", lastName: "" },})const [status, setStatus] = useState("")const check = async (names) => {const isValid = await trigger(names, { shouldFocus: true })setStatus(isValid ? "All checked fields are valid" : "Fix the errors above")}return (<form><input{...register("firstName", { required: "First name is required" })}placeholder="First name"/>{errors.firstName && <p role="alert">{errors.firstName.message}</p>}<input{...register("lastName", { required: "Last name is required" })}placeholder="Last name"/>{errors.lastName && <p role="alert">{errors.lastName.message}</p>}<button type="button" onClick={() => check("lastName")}>Trigger</button><button type="button" onClick={() => check(["firstName", "lastName"])}>Trigger Multiple</button><button type="button" onClick={() => check()}>Trigger All</button><p>{status}</p></form>)}
Video
The following video explains trigger API in detail.
Tips
-
In a multi-step form, validate only the current step's fields before going to the next step:
const onNext = async () => {const isStepValid = await trigger(["firstName", "lastName"], {shouldFocus: true,})if (isStepValid) setStep((step) => step + 1)} -
For fields that depend on each other, such as
passwordandconfirmPassword, use thedepsoption ofregister. You do not need to calltriggerin anonChange. -
Use
trigger("name", { shouldTouch: true })to show an error for a field that the user skipped, without changing its value.
Troubleshooting
if (!trigger("email")) never runs
Why it happens
trigger returns a Promise<boolean>, not a boolean. A promise is always truthy, so !trigger(...) is always false.
Fix
Await the result:
const isValid = await trigger("email")if (!isValid) return
trigger returns true for a field that should fail
Why it happens
trigger only validates fields that are registered. A field whose input is not rendered (for example, a step of a wizard that is not on screen) or a misspelled name has no rules to check, so it passes.
Fix
Check that the field's input is rendered and the name matches its register call. To validate fields that are not on screen, use a resolver, which checks all values against the schema.