setValue
Dynamically update a registered field's value.
</> setValue: UseFormSetValue
This function allows you to dynamically set the value of a registered field and provides options to validate and update the form state. At the same time, it attempts to avoid unnecessary re-renders.
Props
| Name | Description | |
|---|---|---|
namestring | Target a single field or field array by name. | |
valueunknown | The value for the field. This argument is required and cannot be undefined. | |
options | shouldValidateboolean |
|
shouldDirtyboolean |
| |
shouldTouchboolean | Since v7.8.0 Whether to set the input itself to be touched. | |
delayErrorboolean | Since v7.82.0 Opt-in flag that delays the display of the resulting validation error, using the delay (in milliseconds) configured via useForm({ delayError }). Only takes effect when shouldValidate is also set to true. |
-
By default,
setValueonly updates the value and notifieswatch,useWatchandsubscribe. It does not validate the field (even after the form has been submitted) or mark it as dirty or touched. Pass the options you need:setValue("firstName", "Bill", {shouldValidate: true, // update errors and isValidshouldDirty: true, // update dirtyFields and isDirtyshouldTouch: true, // update touchedFields}) -
shouldDirtyonly guarantees that the target field is marked indirtyFieldsimmediately. BecauseisDirtyalways compares current values againstdefaultValues, a later update to any field can trigger adirtyFieldsrecompute that also surfaces other fields whose value already differs from their default — including ones last written withshouldDirty: false. -
You can use methods such as replace or update for a field array; however, they will cause the component to unmount and remount for the targeted field array.
const { update } = useFieldArray({ name: "array" })// unmount fields and remount with updated valueupdate(0, { test: "1", test1: "2" })// will directly update input valuesetValue("array.0.test1", "1")setValue("array.0.test2", "2") -
It's recommended to target the field's name rather than make the second argument a nested object.
setValue("yourDetails.firstName", "value") // ✅ performantsetValue("yourDetails", { firstName: "value" }) ❌ // less performantregister("nestedValue", { value: { test: "data" } }) // register a nested value inputsetValue("nestedValue.test", "updatedData") // ❌ failed to find the relevant fieldsetValue("nestedValue", { test: "updatedData" }) // ✅ setValue finds the input and updates it -
It's recommended to register the input's name before invoking
setValue. To update the entireFieldArray, make sure theuseFieldArrayhook is being executed first.Important: Prefer
replacefromuseFieldArrayfor updating an entire field array — it's the more explicit, purpose-built API, and thissetValueusage may become discouraged in a future version.// you can update an entire Field Array,setValue("fieldArray", [{ test: "1" }, { test: "2" }]) // ⚠️ works, but prefer replace() from useFieldArray// you can use `setValue` on an unregistered inputsetValue("notRegisteredInput", "value") // ✅ prefer it to be registered// the following will implicitly register a single input (without register being invoked)setValue("resultSingleNestedField", { test: "1", test2: "2" }) // ⚠️ works, but registers a field you never called register() on — prefer registering it explicitly// With registered inputs, `setValue` will update both inputs correctly.register("notRegisteredInput.test")register("notRegisteredInput.test2")setValue("notRegisteredInput", { test: "1", test2: "2" }) // ✅ sugar syntax to setValue twice
Examples
Basic
import { useForm } from "react-hook-form"const App = () => {const { register, setValue } = useForm({defaultValues: {firstName: "",},})return (<form><input {...register("firstName", { required: true })} /><button type="button" onClick={() => setValue("firstName", "Bill")}>setValue</button><buttontype="button"onClick={() =>setValue("firstName", "Luo", {shouldValidate: true,shouldDirty: true,})}>setValue options</button></form>)}
Delay Error
// the actual delay (in ms) is configured once at the form levelconst { setValue } = useForm({ delayError: 500 })setValue("firstName", "Bill", {delayError: true, // opt in to the 500ms delay configured aboveshouldValidate: true,})
Dependent Fields
import { useEffect } from "react"import { useForm } from "react-hook-form"type FormValues = {a: stringb: stringc: string}export default function App() {const { watch, register, handleSubmit, setValue, formState } =useForm<FormValues>({defaultValues: {a: "",b: "",c: "",},})const onSubmit = (data: FormValues) => console.log(data)const [a, b] = watch(["a", "b"])useEffect(() => {if (formState.touchedFields.a && formState.touchedFields.b && a && b) {setValue("c", `${a} ${b}`)}}, [setValue, a, b, formState])return (<form onSubmit={handleSubmit(onSubmit)}><input {...register("a")} placeholder="a" /><input {...register("b")} placeholder="b" /><input {...register("c")} placeholder="c" /><input type="submit" /><buttontype="button"onClick={() => {setValue("a", "what", { shouldTouch: true })setValue("b", "ever", { shouldTouch: true })}}>trigger value</button></form>)}