Skip to content

formState

Access real-time form state properties.

</> formState: FormState

This object contains information about the entire form state. It helps you keep track of user interactions with your form application.

Return


NameTypeDescription
isDirtybooleanSet to true after the user modifies any of the inputs.
  • Important: make sure to provide all inputs' defaultValues in useForm, so hook form can have a single source of truth to determine whether the form is dirty.
    const {
    formState: { isDirty, dirtyFields },
    setValue
    } = useForm({ defaultValues: { test: "" } })
    // isDirty: true ✅
    setValue('test', 'change')
    // isDirty: false because getValues() === defaultValues ❌
    setValue('test', '')
  • File-type inputs will need to be managed at the app level due to the ability to cancel file selection and FileList object.
  • Does not support custom objects, classes, or File objects.
dirtyFieldsobjectAn object with the user-modified fields. Make sure to provide all inputs' defaultValues via useForm, so the library can compare against the defaultValues.
  • Important: make sure to provide defaultValues in useForm, so hook form can have a single source of truth to compare each field's dirtiness.
  • Dirty fields do not necessarily represent the isDirty formState, because fields are marked as dirty at the field level rather than the entire form. If you want to determine the entire form state, use isDirty instead.
touchedFieldsobjectAn object containing all the inputs the user has interacted with.
defaultValuesobjectSince v7.37.0 The value that was set at useForm's defaultValues or updated defaultValues via the reset API.
isSubmittedbooleanSet to true after the form is submitted. Will remain true until the reset method is invoked.
isSubmitSuccessfulbooleanIndicates that the form was successfully submitted without any runtime error.
isSubmittingbooleantrue if the form is currently being submitted. false otherwise.
isLoadingbooleanSince v7.41.0 true if the form is currently loading async default values.
  • Important: this prop is only applicable to async defaultValues
    const {
    formState: { isLoading }
    } = useForm({
    defaultValues: async () => await fetch('/api')
    })
submitCountnumberThe number of times the form has been submitted.
isValidbooleanSet to true if the form doesn't have any errors.
  • setError immediately forces isValid to false; this value is not itself derived from validation and will be overwritten the next time validation runs (e.g. on the next onChange, submit, or trigger() call).
isValidatingbooleanSet to true during validation.
validatingFieldsobjectSince v7.51.0 Captures fields that are undergoing asynchronous validation.
errorsobjectAn object with field errors. There is also an ErrorMessage component to retrieve error messages easily.
disabledbooleanSince v7.48.0 Set to true if the form is disabled via the disabled prop in useForm.
isReadybooleanSince v7.56.0 Set to true when formState subscription setup is ready.
  • Renders children before the parent completes setup. If you're using useForm methods (eg. setValue) in a child before the subscription is ready, it can cause issues. Use an isReady flag to ensure the form is initialized before updating state from the child.

    const {
    setValue,
    formState: { isReady }
    } = useForm();
    // Parent component: ✅
    useEffect(() => setValue('test', 'data'), [])
    // Children component: ✅
    useEffect(() => isReady && setValue('test', 'data'), [isReady])
RULES
  • Returned formState is wrapped with a Proxy to improve render performance and skip extra logic if a specific state is not subscribed to. Therefore, make sure you invoke or read it before a render in order to enable the state update.

  • formState is updated in batch. If you want to subscribe to formState via useEffect, make sure that you place the entire formState in the optional array.

    useEffect(() => {
    if (formState.errors.firstName) {
    // do your logic here
    }
    }, [formState]) // ✅
    // ❌ [formState.errors] will not trigger the useEffect
    import { useForm } from "react-hook-form";
    export default function App () {
    const {
    register,
    handleSubmit,
    formState
    } = useForm();
    const onSubmit = (data) => console.log(data);
    React.useEffect(() => {
    console.log("touchedFields", formState.touchedFields);
    },[formState]); // use entire formState object as optional array arg in useEffect, not individual properties of it
    return (
    <form onSubmit={handleSubmit(onSubmit)}>
    <input {...register("test")} />
    <input type="submit" />
    </form>
    );
    };
  • Pay attention to the logical operator when subscribing to formState.

    // ❌ formState.isValid is accessed conditionally,
    // so the Proxy does not subscribe to changes of that state
    return <button disabled={!formState.isDirty || !formState.isValid} />;
    // ✅ read all formState values to subscribe to changes
    const { isDirty, isValid } = formState;
    return <button disabled={!isDirty || !isValid} />;
Examples

import { useForm } from "react-hook-form";
export default function App() {
const {
register,
handleSubmit,
// Read the formState before render to subscribe the form state through the Proxy
formState: { errors, isDirty, isSubmitting, touchedFields, submitCount },
} = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("test")} />
<input type="submit" />
</form>
);
}

Video


Thank you for your support

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

Edit