React useFormStatus — Form Submission States Made Easy
Learn how to use useFormStatus from react-dom to handle form submission loading states. Covers submit buttons, progress indicators, and the key requirement of rendering inside a <form>.
Detailed Explanation
Form Status with useFormStatus
useFormStatus (from react-dom) provides the submission status of the parent <form>. It is the simplest way to show loading states during form submissions.
Basic Submit Button
import { useFormStatus } from "react-dom";
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Saving..." : "Save"}
</button>
);
}
The Critical Requirement
useFormStatus must be called from a component that is rendered inside a <form>. It does NOT work in the form component itself:
// WRONG -- does not work
function Form() {
const { pending } = useFormStatus(); // Always { pending: false }
return <form action={action}>...</form>;
}
// CORRECT -- component rendered inside <form>
function Form() {
return (
<form action={action}>
<SubmitButton /> {/* useFormStatus works here */}
</form>
);
}
Full Status Object
const status = useFormStatus();
// status.pending: boolean -- true while form is submitting
// status.data: FormData | null -- the submitted form data
// status.method: string -- "get" or "post"
// status.action: string | function | null -- the form action
Progress Indicator Pattern
function FormProgress() {
const { pending, data } = useFormStatus();
if (!pending) return null;
return (
<div className="progress-bar">
Submitting {data?.get("name")}...
</div>
);
}
Important: react-dom, not react
Unlike other hooks, useFormStatus is imported from react-dom, not react. This is because it is specific to DOM form elements and does not apply to other React renderers like React Native.
Use Case
Use useFormStatus for disabling submit buttons during submission, showing loading spinners in forms, displaying progress indicators, and building reusable form components with built-in loading states. It pairs well with React Server Actions.