<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>
To create interactive controls for submitting information, render the built-in browser <form>
component.
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
Props
<form>
supports all common element props.
action
: a URL or function. When a URL is passed to action
the form will behave like the HTML form component. When a function is passed to action
the function will handle the form submission. The function passed to action
may be async and will be called with a single argument containing the form data of the submitted form. The action
prop can be overridden by a formAction
attribute on a <button>
, <input type="submit">
, or <input type="image">
component.
Caveats
- When a function is passed to
action
orformAction
the HTTP method will be POST regardless of value of themethod
prop.
Usage
Handle form submission on the client
Pass a function to the action
prop of form to run the function when the form is submitted. Unlike a conventional HTML action, the form won’t call a server endpoint when a client function is passed to action
prop of form. formData
will be passed to the function as an arrgument so you can access the data submitted by the form.
export default function Search() { function search(formData) { const query = formData.get("query"); alert(`You searched for '${query}'`); } return ( <form action={search}> <input name="query" /> <button type="submit">Search</button> </form> ); }
Handle form submission with a Server Action
Render a <form>
with a input and submit button. Pass a server action (a function marked with 'use server'
to the action
prop of form to run the function when the form is submitted.
This is similar to the way forms work when a URL is passed to the action
prop. The ability to submit forms without JavaScript enables users to submit forms before JavaScript has had a chance to load. This can be benificial to users who have a slow connection, device, or have JavaScript disabled.
You can use hidden form fields to provide data to the <form>
’s action. The hidden form field data can be access via the formData
argument pass to the function that is passed to the action
prop of <form>
.
import { updateCart } from './lib.js';
function AddToCart({productId}) {
async function addToCart(formData) {
'use server'
const productId = formData.get('productId')
await updateCart(productId)
}
return (
<form action={addToCart}>
<input type="hidden" name="productId" value={productId} />
<button type="submit">Add to Cart</button>
</form>
);
}
In lieu, of using hidden form fields to provide data to the <form>
’s action, you can call the bind
method to supply it with extra arguments. This will bind a new argument (productId
) to the function in addition to the formData
that is passed as a argument to the function.
import { updateCart } from './lib.js';
function AddToCart({productId}) {
async function addToCart(productId, formData) {
"use server";
await updateCart(productId)
}
const addProductToCart = addToCart.bind(null, productId);
return (
<form action={addProductToCart}>
<button type="submit">Add to Cart</button>
</form>
);
}
When <form>
is rendered by a Server Component, and a Server Action is passed to the <form>
’s action
prop, the form is progressively enhanced.
Display a pending state during form submission
To display a pending state when a form is being submitted, 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} />; }
To learn more about the useFormStatus
Hook see the reference documentation.
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 { useOptimistic, useState, useRef } from "react"; import { deliverMessage } from "./actions.js"; function Thread({ messages, sendMessage }) { const formRef = useRef(); async function formAction(formData) { addOptimisticMessage(formData.get("message")); formRef.current.reset(); await sendMessage(formData); } const [optimisticMessages, addOptimisticMessage] = useOptimistic( messages, (state, newMessage) => [ ...state, { text: newMessage, sending: true } ] ); return ( <> {optimisticMessages.map((message, index) => ( <div key={index}> {message.text} {!!message.sending && <small> (Sending...)</small>} </div> ))} <form action={formAction} ref={formRef}> <input type="text" name="message" placeholder="Hello!" /> <button type="submit">Send</button> </form> </> ); } export default function App() { const [messages, setMessages] = useState([ { text: "Hello there!", sending: false, key: 1 } ]); async function sendMessage(formData) { const sentMessage = await deliverMessage(formData.get("message")); setMessages([...messages, { text: 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 the 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> ); }
Display a form submission error without JavaScript
Displaying a form submissions error message without JavaScript requires that:
<form>
be rendered by a Server Component- the function passed to the
<form>
’saction
prop be a Server Action - the
useFormState
Hook be used to display the error message
useFormState
takes two parameters: an Server Action and a inital state. useFormState
returns two values, a state variable and a action. The action returned by useFormState
should be passed to the action
prop of the form. The state varible returned by useFormState
can be used to displayed an error message. The value returned by the Server Action passed to useFormState
will be used to update the state variable.
import { useFormState } from "react-dom"; import { signUpNewUser } from "./api"; export default function Page() { async function signup(prevState, formData) { "use server"; const email = formData.get("email"); try { await signUpNewUser(email); alert(`Added "${email}"`); } catch (err) { return err.toString(); } } const [message, formAction] = useFormState(signup, null); return ( <> <h1>Signup for my newsletter</h1> <p>Signup with the same email twice to see an error</p> <form action={formAction} id="signup-form"> <label htmlFor="email">Email: </label> <input name="email" id="email" placeholder="react@example.com" /> <button>Sign up</button> {!!message && <p>{message}</p>} </form> </> ); }
Handling multiple submission types
Forms can be designed to handle multiple submission actions based on the button pressed by the user. Each button inside a form can be associated with a distinct action or behavior by setting the formAction
prop. 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 submit a article for review by default but have a seperate button with formAction
set to save the article as a draft.
export default function Search() { function publish(formData) { const content = formData.get("content"); const button = formData.get("button"); alert(`'${content}' was published with the '${button}' button`); } function save(formData) { const content = formData.get("content"); alert(`Your draft of '${content}' has been saved!`); } return ( <form action={publish}> <textarea name="content" rows={4} cols={40} /> <br /> <button type="submit" name="button" value="submit">Publish</button> <button formAction={save}>Save draft</button> </form> ); }