← Back
Edit Post
Title
Description
SubmitButton pattern, child component constraint, localized form feedback.
Content
Markdown supported
# useFormStatus When a form is submitting, users need feedback exactly where they initiated the action. A global loading bar doesn't tell them which button is working. `useFormStatus` provides the pending state of the nearest parent form—enabling localized, contextual feedback. The hook returns `{ pending, data, method, action }`, but `pending` is what you'll use most. It becomes true when the form submits and false when the action completes. ## The SubmitButton Pattern The most common use is a reusable submit button that shows its own loading state: ```tsx 'use client'; import { useFormStatus } from 'react-dom'; export function SubmitButton({ children }) { const { pending } = useFormStatus(); return ( <Button type="submit" disabled={pending}> {pending ? 'Saving...' : children} </Button> ); } ``` Drop this into any form—no prop drilling, no context providers, no state management: ```tsx <form action={createPost}> <Input name="title" /> <SubmitButton>Create Post</SubmitButton> </form> ``` The button automatically shows a spinner during submission and disables to prevent double-clicks. ## The Child Component Constraint Here's the critical detail: `useFormStatus` must be called from a **child component** of the form. It doesn't work in the same component that renders the form: ```tsx // ❌ Won't work - same component as form function BadForm() { const { pending } = useFormStatus(); // Always false return <form action={action}>...</form>; } // ✅ Works - SubmitButton is a separate child component function GoodForm() { return ( <form action={action}> <SubmitButton>Save</SubmitButton> </form> ); } ``` This constraint exists because React needs to track which form the status belongs to—and that relationship is established through the component tree. ## Beyond Buttons Use the pattern for any form feedback: ```tsx function FormProgress() { const { pending } = useFormStatus(); if (!pending) return null; return <Progress value={undefined} className="w-full" />; } ``` The principle: button click → button feedback. Keep pending indicators close to where users took action.
Published
Save Changes
Cancel