diff --git a/src/content/reference/react-dom/components/form.md b/src/content/reference/react-dom/components/form.md index 10e9c67940e..f0643fdb066 100644 --- a/src/content/reference/react-dom/components/form.md +++ b/src/content/reference/react-dom/components/form.md @@ -42,27 +42,23 @@ To create interactive controls for submitting information, render the [built-in #### Caveats {/*caveats*/} -* When a function is passed to `action` or `formAction` the HTTP method will be POST regardless of value of the `method` prop. +* When a function is passed to `action` or `formAction` the HTTP method will be POST regardless of the value of the `method` prop. +* When a function is passed to `action` or `formAction`, React resets all [uncontrolled](/reference/react-dom/components/input#reading-the-input-values-when-submitting-a-form) field elements after the action succeeds. See [Preserving form values after submission](#preserve-form-values-after-submission). --- ## Usage {/*usage*/} -### Handle form submission with an event handler {/*handle-form-submission-with-an-event-handler*/} +### Handling form submission with an event handler {/*handle-form-submission-with-an-event-handler*/} -Pass a function to the `onSubmit` event handler to run code when the form is submitted. By default, the browser sends the form data to the current URL and refreshes the page, so call [`e.preventDefault()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) to override that behavior. +Pass a function to the `onSubmit` event handler to run code when the form is submitted. By default, the browser sends the form data to the current URL and refreshes the page. Call [`e.preventDefault()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) in your handler to override that behavior. -This example reads the submitted values with [`new FormData(e.target)`](https://developer.mozilla.org/en-US/docs/Web/API/FormData), which collects every field by its `name`. This keeps the inputs [uncontrolled](/reference/react-dom/components/input#reading-the-input-values-when-submitting-a-form). If you instead [control an input with state](/reference/react-dom/components/input#controlling-an-input-with-a-state-variable), read from that state on submit rather than from `FormData`. ```js src/App.js export default function Search() { function handleSubmit(e) { - // Prevent the browser from reloading the page - e.preventDefault(); - - // Read the form data const form = e.target; const formData = new FormData(form); const query = formData.get("query"); @@ -86,9 +82,22 @@ Reading form data with `onSubmit` works in every version of React and gives you -### Handle form submission with an action prop {/*handle-form-submission-with-an-action-prop*/} +### Handling form submission with an action prop {/*handle-form-submission-with-an-action-prop*/} + +Pass a function to the `action` prop of `
` to handle submission. When the form is submitted, React calls your function with a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object containing the field values. + +Give each input a `name` attribute so its value is included in `FormData`. You can use [uncontrolled](/reference/react-dom/components/input#reading-the-input-values-when-submitting-a-form) inputs instead of controlled `value`/`onChange` pairs, and you don't need an `onSubmit` handler or `e.preventDefault()`. -Pass a function to the `action` prop of form to run the function when the form is submitted. [`formData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) will be passed to the function as an argument so you can access the data submitted by the form. This differs from the conventional [HTML action](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#action), which only accepts URLs. Unlike `onSubmit`, an `action` runs in a [Transition](/reference/react/useTransition) and calling `e.preventDefault()` isn't needed. After the `action` function succeeds, all uncontrolled field elements in the form are reset. +This extends the [HTML `action` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#action), which only accepts a URL, to also accept a function. Because the form stays a native HTML form, it can be submitted before JavaScript loads; with a [Server Function](/reference/rsc/server-functions), it works without JavaScript enabled. + +When you pass a function to `action`, React: + +* Runs the submission function in a [Transition](/reference/react/useTransition). +* Tracks pending state so child components can read it with [`useFormStatus`](/reference/react-dom/hooks/useFormStatus). +* Sends thrown errors to the nearest error boundary. +* Works with [`useActionState`](/reference/react/useActionState) and [`useOptimistic`](/reference/react/useOptimistic) for form state and optimistic UI. + +After the function succeeds, React resets all [uncontrolled](/reference/react-dom/components/input#reading-the-input-values-when-submitting-a-form) field elements in the form. To keep their values, see [Preserving form values after submission](#preserve-form-values-after-submission). @@ -109,11 +118,12 @@ export default function Search() { -### Handle form submission with a Server Function {/*handle-form-submission-with-a-server-function*/} + +### Handling form submission with a Server Function {/*handle-form-submission-with-a-server-function*/} Render a `` with an input and submit button. Pass a Server Function (a function marked with [`'use server'`](/reference/rsc/use-server)) to the `action` prop of form to run the function when the form is submitted. -Passing a Server Function to `` allow users to submit forms without JavaScript enabled or before the code has loaded. This is beneficial to users who have a slow connection, device, or have JavaScript disabled and is similar to the way forms work when a URL is passed to the `action` prop. +Passing a Server Function to `` allows users to submit forms without JavaScript enabled or before the code has loaded. This is beneficial to users who have a slow connection, device, or have JavaScript disabled and is similar to the way forms work when a URL is passed to the `action` prop. You can use hidden form fields to provide data to the ``'s action. The Server Function will be called with the hidden form field data as an instance of [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData). @@ -157,7 +167,87 @@ function AddToCart({productId}) { When `` is rendered by a [Server Component](/reference/rsc/use-client), and a [Server Function](/reference/rsc/server-functions) is passed to the ``'s `action` prop, the form is [progressively enhanced](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement). -### Display a pending state during form submission {/*display-a-pending-state-during-form-submission*/} +### Preserving form values after submission {/*preserve-form-values-after-submission*/} + +The browser clears a form's input state on submit. A URL `action` follows this same behavior. React does the same when `action` is a function, so your form works consistently before and after JavaScript loads. + +When you pass a function to `action` or `formAction`, React resets the form's [uncontrolled fields](/reference/react-dom/components/input#reading-the-input-values-when-submitting-a-form) after the action succeeds. The reset only applies to uncontrolled fields, so [inputs you control with state](/reference/react-dom/components/input#controlling-an-input-with-a-state-variable) are never cleared. + +To keep the values of uncontrolled fields, add an `onSubmit` handler that calls `e.preventDefault()` and runs the action inside a [Transition](/reference/react/useTransition). Keep the `action` prop on the form so it still works before JavaScript loads. + + + +```js src/App.js +import { useTransition } from "react"; +import { submitForm } from "./api.js"; + +export default function EditForm() { + const [isPending, startTransition] = useTransition(); + + function handleSubmit(e) { + // Stop React from resetting the form after the action succeeds + e.preventDefault(); + const formData = new FormData(e.target); + startTransition(async () => { + await submitForm(formData); + }); + } + + return ( + + + + + ); +} +``` + +```js src/api.js hidden +export async function submitForm(formData) { + await new Promise((res) => setTimeout(res, 1000)); +} +``` + +
+ +Because you call the action manually from `onSubmit`, [`useFormStatus`](/reference/react-dom/hooks/useFormStatus) won't report its pending state. Read `isPending` from the same [`useTransition`](/reference/react/useTransition) call instead. + + + +#### Resetting only some fields, or resetting on the server {/*resetting-only-some-fields*/} + +The `onSubmit` approach keeps every uncontrolled field. When you need finer control, two other patterns are available: + +* **Reset from your own action API.** If you build an action-based API and still want the form to reset after the action runs, call the `requestFormReset` API from `react-dom` with the form element inside the Transition. + +* **Reset to server-provided values.** When an action validates input on the server, return the submitted `FormData` and pass it to each field's `defaultValue`. React restores those values instead of clearing them, and the form keeps working before JavaScript loads: + +```js +import { useActionState } from "react"; +import { submitForm } from "./actions.js"; + +function EditForm() { + // The action returns { submitted: formData, error } on failure + const [state, formAction] = useActionState(submitForm, {}); + const values = state.submitted ?? new FormData(); + return ( +
+ + {state.error &&

{state.error}

} + +
+ ); +} +``` + +Return the original `FormData` object rather than a new one so React can restore the values even before JavaScript has loaded. + +
+ + +### Displaying a pending state during form submission {/*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 `
` and read the `pending` property returned. Here, we use the `pending` property to indicate the form is submitting. @@ -266,9 +356,7 @@ export async function deliverMessage(message) { ``` - -[//]: # 'Uncomment the next line, and delete this line after the `useOptimistic` reference documentation page is published' -[//]: # 'To learn more about the `useOptimistic` Hook see the [reference documentation](/reference/react/useOptimistic).' +To learn more about the `useOptimistic` Hook see the [reference documentation](/reference/react/useOptimistic). ### Handling form submission errors {/*handling-form-submission-errors*/} @@ -312,7 +400,7 @@ export default function Search() { -### Display a form submission error without JavaScript {/*display-a-form-submission-error-without-javascript*/} +### Displaying a form submission error without JavaScript {/*display-a-form-submission-error-without-javascript*/} Displaying a form submission error message before the JavaScript bundle loads for progressive enhancement requires that: @@ -372,28 +460,45 @@ Learn more about updating state from a form action with the [`useActionState`](/ ### Handling multiple submission types {/*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. +A form can have more than one submit button, each running a different action. Set the `formAction` prop on a `