| title | useFormStatus |
|---|---|
| canary | true |
The useFormStatus Hook is currently only available in React's Canary and experimental channels. Learn more about React's release channels here.
useFormStatus is a Hook that gives you status information of the last form submission.
const { pending, data, method, action } = useFormStatus();The useFormStatus Hook provides status information of the last form submission.
import { useFormStatus } from "react-dom";
import action from './actions';
function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>Submit</button>
}
export default App() {
return (
<form action={action}>
<Submit />
</form>
);
}To get status information, the Submit component must be rendered within a <form>. The Hook returns information like the pending property which tells you if the form is actively submitting.
In the above example, Submit uses this information to disable <button> presses while the form is submitting.
useFormStatus does not take any parameters.
A status object with the following properties:
-
pending: A boolean. Iftrue, this means the parent<form>is pending submission. Otherwise,false. -
data: An object implementing theFormData interfacethat contains the data the parent<form>is submitting. If there is no active submission or no parent<form>, it will benull. -
method: A string value of either'get'or'post'. This represents whether the parent<form>is submitting with either aGETorPOSTHTTP method. By default, a<form>will use theGETmethod and can be specified by themethodproperty.
action: A reference to the function passed to theactionprop on the parent<form>. If there is no parent<form>, the property isnull. If there is a URI value provided to theactionprop, or noactionprop specified,status.actionwill benull.
- The
useFormStatusHook must be called from a component that is rendered inside a<form>. useFormStatuswill only return status information for a parent<form>. It will not return status information for any<form>rendered in that same component or children components.
To display a pending state while a form is submitting, you can call the useFormStatus Hook in a component rendered in a <form> and read the pending property returned.
Here, we use the pending property to indicate the form is submitting.
import { useFormStatus } from "react-dom";
import { submitForm } from "./actions.js";
function Submit() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Submitting..." : "Submit"}
</button>
);
}
function Form({ action }) {
return (
<form action={action}>
<Submit />
</form>
);
}
export default function App() {
return <Form action={submitForm} />;
}export async function submitForm(query) {
await new Promise((res) => setTimeout(res, 1000));
}{
"dependencies": {
"react": "canary",
"react-dom": "canary",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}useFormStatus will not return status information for a <form> rendered in the same component. {/useformstatus-will-not-return-status-information-for-a-form-rendered-in-the-same-component/}
The useFormStatus Hook only returns status information for a parent <form> and not for any <form> rendered in the same component calling the Hook, or child components.
function Form() {
// 🚩 `pending` will never be true
// useFormStatus does not track the form rendered in this component
const { pending } = useFormStatus();
return <form action={submit}></form>;
}Instead call useFormStatus from inside a component that is located inside <form>.
function Submit() {
// ✅ `pending` will be derived from the form that wraps the Submit component
const { pending } = useFormStatus();
return <button disabled={pending}>...</button>;
}
function Form() {
// This is the <form> `useFormStatus` tracks
return (
<form action={submit}>
<Submit />
</form>
);
}You can use the data property of the status information returned from useFormStatus to display what data is being submitted by the user.
Here, we have a form where users can request a username. We can use useFormStatus to display a temporary status message confirming what username they have requested.
import {useState, useMemo, useRef} from 'react';
import {useFormStatus} from 'react-dom';
export default function UsernameForm() {
const {pending, data} = useFormStatus();
const [showSubmitted, setShowSubmitted] = useState(false);
const submittedUsername = useRef(null);
const timeoutId = useRef(null);
useMemo(() => {
if (pending) {
submittedUsername.current = data?.get('username');
if (timeoutId.current != null) {
clearTimeout(timeoutId.current);
}
timeoutId.current = setTimeout(() => {
timeoutId.current = null;
setShowSubmitted(false);
}, 2000);
setShowSubmitted(true);
}
}, [pending, data]);
return (
<>
<label>Request a Username: </label><br />
<input type="text" name="username" />
<button type="submit" disabled={pending}>
{pending ? 'Submitting...' : 'Submit'}
</button>
{showSubmitted ? (
<p>Submitted request for username: {submittedUsername.current}</p>
) : null}
</>
);
}import UsernameForm from './UsernameForm';
import { submitForm } from "./actions.js";
export default function App() {
return (
<form action={submitForm}>
<UsernameForm />
</form>
);
}export async function submitForm(query) {
await new Promise((res) => setTimeout(res, 1000));
}{
"dependencies": {
"react": "canary",
"react-dom": "canary",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}useFormStatus will only return status information for a parent <form>.
If the component that calls useFormStatus is not nested in a <form>, status.pending will always return false. Verify useFormStatus is called in a component that is a child of a <form> element.
useFormStatus will not track the status of a <form> rendered in the same component. See Pitfall for more details.