Skip to content

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


NameTypeDescriptionExample
nameundefinedTriggers validation on all fields.trigger()
stringTriggers validation on a specific field value by nametrigger("yourDetails.firstName")
string[]Triggers validation on multiple fields by name.trigger(["yourDetails.lastName"])
shouldFocusbooleanSince 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 })
shouldTouchbooleanSince 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 })
RULES

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: string
lastName: 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>
)
}

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 password and confirmPassword, use the deps option of register. You do not need to call trigger in an onChange.

  • 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.