Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

useFormStatus returns pending: false when the component calling it is not nested inside the <form> it is supposed to track. The fix is to move the hook into a small child component, such as SubmitButton, and render that child inside the form. The button then reads the status of its parent form, and its disabled state and label can follow the submission.

Why pending stays false

useFormStatus does not look at whichever form is drawn nearby. It reads the status of a parent form, meaning a <form> that encloses the component calling the hook. If the calling component sits beside the form, sits above it in the tree, or is the same component that returns the form, there is no enclosing form for the hook to read, so pending never becomes true.

React’s useFormStatus reference states this case in its troubleshooting section, under the heading “status.pending is never true“: if the component that calls useFormStatus is not nested in a <form>, status.pending will always be false.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The hook is imported from react-dom and takes no parameters:

import { useFormStatus } from 'react-dom';

The pattern that never works

The most common version of the mistake puts the hook in the same component that renders the form:

function ContactForm({ action }) {
  const { pending } = useFormStatus(); // not inside a form: always false

  return (
    <form action={action}>
      <button type="submit" disabled={pending}>Submit</button>
    </form>
  );
}

The button looks correct, but it never disables during submission, because the hook is called one level above the form it is meant to observe.

The SubmitButton fix

Move the hook and the button into their own component, then render that component as a child of the form:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending } = useFormStatus();

  return (
    <button type="submit" disabled={pending}>
      {pending ? 'Submitting…' : 'Submit'}
    </button>
  );
}

function ContactForm({ action }) {
  return (
    <form action={action}>
      {/* fields */}
      <SubmitButton />
    </form>
  );
}

SubmitButton is rendered inside the form, so the hook finds that form’s status. ContactForm only renders the form and no longer calls the hook, so nothing is read from the wrong place. React’s form documentation describes this same arrangement, a component rendered within a form that displays pending state during submission.

Placement compared

Where the hook is called Form it can observe Result for pending
Same component that returns the <form> None, because the calling component is not inside the form Always false
Component rendered beside the form, outside it None Always false
Child component rendered inside the <form> The enclosing form Reflects that form’s submission in progress

What useFormStatus returns

The hook returns a status object with four properties. The reference documents the following values:

Property Value and meaning
pending A boolean that is true while the parent form’s submission is in progress. This is the value to use for disabled states and feedback text.
data The submitted FormData while a submission is active; null otherwise.
method Indicates whether the parent form uses GET or POST.
action In the documented case where the parent form’s action prop is a function, this is that function. In the non-function and absent cases the reference describes, it is null.

Diagnostic checklist

  1. Find the component that calls useFormStatus in your code.
  2. Open the rendered tree and confirm that component is a descendant of the <form> element. A component beside the form, or one that wraps the form, will not work.
  3. If the same component also returns the <form>, move the hook and the button into a child component, as in the SubmitButton example above.
  4. Confirm the child is rendered inside the form’s children, even if intermediate components sit between them.
  5. Test with a form whose action prop is a function, the arrangement used in React’s reference examples. Watch the button disable while the submission runs and re-enable afterward.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Scope of the hook

  • useFormStatus is part of React DOM’s browser hooks. React’s React DOM hooks overview separates these from hooks supported in non-browser environments, such as native iOS, Android, and Windows applications, so this fix applies to web React DOM apps.
  • The hook only reports status. It does not define the form’s action or handle the submitted data, so the server-side or client-side action function still needs to be written separately.

Sources for this article: React’s useFormStatus reference page (return values, parent-form scope, troubleshooting section), React’s <form> reference page (pending-state usage), and React’s “Built-in React DOM Hooks” overview.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.