<form>
The built-in browser <form>
component lets you create interactive controls for submitting information.
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
Reference
<form>
The built-in browser <form>
component lets you create interactive controls for submitting information.
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
🚧 Props
<form>
supports all common element props.
Additionally, <form>
supports these props:
action
: A boolean. Specifies what to do when a form is submitted. The form data can be handled with client or server side code.- 🚧
🚧 Forms can contain one or more of the following tags:
- [
<input>
] - [
<textarea>
] - [
<button>
]- [
formAction
] prop that overrides<form>
’saction
prop
- [
- [
<select>
] - [
<option>
] - [
<optgroup>
] - [
<fieldset>
] - [
<label>
] - [
<output>
] - 🚧
🚧 Caveats
- 🚧
Usage
🚧 Submitting forms to the server
Render a <form>
with a input and submit button. Pass a function marked with 'use server';
to the action
prop of form to run the function when the form is submitted.
'use client' import { search } from './actions.js' export default function Search() { return ( <form action={search}> <input name="query" /> <button type="submit">Search</button> </form> ); }
Handling form submissions on the client
Render a <form>
with a input and submit button. Pass a function to the action
prop of form to run the function when the form is submitted.
export default function Search() { function search(formAction) { const query = formAction.get("query"); alert(`You searched for '${query}'`); } return ( <form action={search}> <input name="query" /> <button type="submit">Search</button> </form> ); }
Display a pending state during form submission
You can track the status of a form submission with the useFormStatus
Hook. The useFormStatus
Hook provides information on the form’s state, like when the form is pending. The pending
property indicates whether the form is currently in the process of being submitted. You can use this property to update the UI while the form is being submitted like disabling buttons or alterning wording.
import { experimental_useFormStatus as useFormStatus } from "react-dom"; import { submitForm } from "./actions.js"; function Button() { const { pending } = useFormStatus(); return ( <button type="submit" disabled={pending}> {pending ? "Submitting..." : "Submit"} </button> ); } function Form({ action }) { return ( <form action={action}> <Button /> </form> ); } export default function App() { return <Form action={submitForm} />; }
Optimistically updating form data
The useOptimistic
Hook provides a way to optimistically update the user interface before a background operation, like a network request, completes. In the context of forms, this technique helps to make apps feel more responsive. When a user submits a form, instead of waiting for the server’s response to reflect the changes, the interface is immediately updated with the expected outcome.
For example, when a user types a message into the form and hits the “Send” button, the useOptimistic
Hook allows the message to immediately appear in the list with a “Sending…” label, even before the message is actually sent to a server. This “optimistic” approach gives the impression of speed and responsiveness. The form then attempts to truly send the message in the background. Once the server confirms the message has been received, the “Sending…” label is removed.
import { experimental_useOptimistic as useOptimistic, useState } from "react"; import { deliverMessage } from "./actions.js"; function Thread({ messages, sendMessage }) { const [optimisticMessages, addOptimisticMessage] = useOptimistic( messages, (state, newMessage) => [ ...state, { message: newMessage, sending: true } ] ); return ( <div> {optimisticMessages.map((m, i) => ( <div key={i}> {m.message} <small>{m.sending ? " (Sending...)" : ""}</small> </div> ))} <form action={sendMessage} onSubmit={async (e) => { e.preventDefault(); const form = e.currentTarget; const formData = new FormData(form); addOptimisticMessage(formData.get("message")); form.reset(); await sendMessage(formData); }} > <input type="text" name="message" placeholder="Hello!" /> <button type="submit">Send</button> </form> </div> ); } export default function App() { const [messages, setMessages] = useState([ { message: "Hello there!", sending: false, key: 1 } ]); async function sendMessage(formData) { const sentMessage = await deliverMessage(formData.get("message")); setMessages([...messages, { message: sentMessage }]); } return <Thread messages={messages} sendMessage={sendMessage} />; }
Handling form submission errors
In some cases the function called by a <form>
’s action
prop throw an error. You can handle these errors by wrapping <form>
in an Error Boundary. If function called by a <form>
’s action
prop throws an error the fallback for the error boundary will be displayed.
import { ErrorBoundary } from "react-error-boundary"; import { action } from "./actions.js" export default function Search() { return ( <ErrorBoundary fallback={<p>There was an error while submitting the form</p>}> <form action={action}> <input name="query" /> <button type="submit">Search</button> </form> </ErrorBoundary> ); }
Processing forms differently with different submit buttons
Forms can be designed to handle multiple submission actions based on the button pressed by the user. Each button can be associated with a distinct action or behavior. When a user taps a specific button, the form is submitted, and a corresponding action, defined by that button’s attributes and action, is executed. For instance, a form might allow users to either save their input as a draft or submit it for review with separate buttons.
export default function Search() { function publish(formAction) { const content = formAction.get("content"); const button = formAction.get("button"); alert(`'${content}' was published with the '${button}' button`); } function save(formAction) { const content = formAction.get("content"); alert(`Your draft of '${content}' has been saved!`); } return ( <form action={publish}> <textarea name="content" rows={4} cols={40} /> <button type="submit" name="button" value="submit">Publish</button> <button formAction={save}>Save draft</button> </form> ); }