Skip to content

createFormControl

Standalone form state outside of React components.

Since v7.55.0

This function creates the entire form state subscription and allows you to subscribe to updates with or without a React component. You can use this function without needing the React Context API.

Props


NameTypeDescription
...propsObjectUseFormProps

Returns


NameTypeDescription
formControlObjectcontrol object for useForm hook
controlObjectcontrol object for useController, useFormState, useWatch
subscribeFunctionfunction to subscribe for form state updates without rendering
...returnsFunctionsuseForm return methods
NOTES
  • This function is completely optional; you can consider using this instead of the useFormContext API. - You may find it useful if you would like to subscribe to formState while skipping React re-renders.
RULES
  • You should either use this API or the Context API

    const props = createFormControl()
    <FormProvider {...props} /> // ❌ You don't need a provider
    <input {...props.register("name")} /> // ✅ Use method directly from createFormControl
  • Create the control once. Passing a new instance to useForm({ formControl }) re-initializes the form. A control created at module scope is a single form shared by every component that uses it and, during server rendering, by every request. For one form per component instance, create it lazily:

    const [form] = useState(() => createFormControl({ defaultValues }))
    const { register } = useForm({ formControl: form.formControl })
Examples:

const { formControl, control, handleSubmit, register } = createFormControl({
mode: "onChange",
defaultValues: {
firstName: "Bill",
},
})
function App() {
useForm({
formControl,
})
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register("name")} />
<FormState />
<ControlledInput />
</form>
)
}
function FormState() {
const { isDirty } = useFormState({
control, // no longer need context api
})
return isDirty ? <p>Form is dirty.</p> : null
}
function ControlledInput() {
const { field } = useController({
control, // no longer need context api
name: "firstName",
})
return <input {...field} />
}
const { formControl, register } = createFormControl(props)
formControl.subscribe({
formState: {
isDirty: true,
values: true,
},
callback: (formState) => {
if (formState.isDirty) {
// do something here
}
if (formState.values.test.length > 3) {
// do something here
}
},
})
function App() {
const { register } = useForm({
formControl,
})
return (
<form>
<input {...register("test")} />
</form>
)
}