form action prop accepts URL or function
The action prop on a form component accepts either a URL or a function. When a URL is passed, the form behaves like the standard HTML form component. When a function is passed, the function handles form submission in a Transition following the Action prop pattern. The function receives the form data as a single argument containing FormData 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.
form action function receives FormData argument
When a function is passed to the action prop of a form, the function is called with a single argument containing the FormData of the submitted form. This allows the function to access all form field values submitted by the form.
form with action function uses POST HTTP method
When a function is passed to action or formAction, the HTTP method will be POST regardless of the value of the method prop.
form action prop runs in Transition
When a function is passed to the action prop, the form submission runs in a Transition. This differs from using onSubmit, which does not run in a Transition. Running in a Transition allows React to track the pending state, send thrown errors to the nearest error boundary, and enable use of hooks like useActionState and useOptimistic.
form action prop can be a Server Function
The action prop on a form can accept a Server Function marked with 'use server'. Passing a Server Function to form action allows users to submit forms without JavaScript enabled or before code has loaded, providing progressive enhancement. The form will work similar to how it works when a URL is passed to the action prop.
form action function resets uncontrolled fields on success
After the action function succeeds, all uncontrolled field elements in the form are automatically reset.
form with action function does not need e.preventDefault()
When using an action prop, calling e.preventDefault() is not needed. The form submission is handled by React's Transition system automatically.
onSubmit event handler for form submission
You can pass a function to the onSubmit event handler of a form 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 you should call e.preventDefault() to override that behavior. This approach works in every version of React and gives you direct access to the submit event.
form example with onSubmit handler
export default function Search() {
function handleSubmit(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const query = formData.get("query");
alert(`You searched for '${query}'`);
}
return (
<form onSubmit={handleSubmit}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}
This example demonstrates reading form data with onSubmit by preventing the default browser behavior and using FormData API to access submitted values.
form example with action function
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>
);
}
This example demonstrates passing a function to the action prop to handle form submission. The function receives FormData and no e.preventDefault() is needed.
form with Server Function action
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>
);
}
This example shows passing a Server Function marked with 'use server' to the action prop and using hidden form fields to provide data to the Server Function.
form action function with bind method
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>
);
}
This example demonstrates using the bind method to supply extra arguments to a Server Function in addition to the FormData that is passed as an argument. The bound function can receive multiple parameters.
formAction prop overrides form action prop
The formAction attribute on a button, input type="submit", or input type="image" component can override the action prop of the parent form. This allows different buttons in a form to submit to different actions.
form example with multiple submission buttons
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>
);
}
This example demonstrates handling multiple submission types by using the formAction prop on different buttons to execute different functions based on which button the user presses.
useFormStatus hook returns pending property
The useFormStatus hook can be called in a component rendered in a form to read the pending property. The pending property is a boolean that indicates whether the form is currently being submitted. This can be used to display a pending state, such as disabling the submit button and showing 'Submitting...' text while the form is being submitted.
useOptimistic hook for optimistic form updates
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, when a user submits a form, instead of waiting for the server's response, the interface is immediately updated with the expected outcome. This makes applications feel more responsive.
form example with optimistic updates
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) => [...messages, { text: sentMessage }]);
}
return <Thread messages={messages} sendMessage={sendMessage} />;
}
This example demonstrates using useOptimistic to immediately display a message with a 'Sending...' label when the user submits a form, before the message is actually sent to the server.
form submission errors thrown to error boundary
If the function called by a form's action prop throws an error, the error is sent to the nearest error boundary. You can wrap a form in an Error Boundary to handle these errors and display a fallback UI.
form example with error boundary
import { ErrorBoundary } from "react-error-boundary";
export default function Search() {
function search() {
throw new Error("search error");
}
return (
<ErrorBoundary
fallback={<p>There was an error while submitting the form</p>}
>
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
</ErrorBoundary>
);
}
This example demonstrates wrapping a form in an Error Boundary to catch and handle errors thrown by the action function.
useActionState hook for form submission with error display
useActionState takes two parameters: a Server Function and an initial state. It returns two values: a state variable and an action. The action should be passed to the form's action prop, and the state variable can be used to display error messages. The value returned by the Server Function is used to update the state variable.
form example with useActionState error handling
import { useActionState } from "react";
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, signupAction] = useActionState(signup, null);
return (
<>
<h1>Signup for my newsletter</h1>
<p>Signup with the same email twice to see an error</p>
<form action={signupAction} 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>
</>
);
}
This example demonstrates using useActionState with a Server Function to handle form submission errors and display error messages before JavaScript bundles load.
form supports all common element props
The form component supports all common element props that are available on standard React DOM elements.
Form components are controlled by passing value prop
The form components `<input>`, `<select>`, and `<textarea>` are special in React because passing the `value` prop to them makes them controlled components.
input controlled vs uncontrolled caveats
Checkboxes need checked or defaultChecked, not value or defaultValue. If a text input receives a string value prop, it is treated as controlled. If a checkbox or radio button receives a boolean checked prop, it is treated as controlled. An input cannot be both controlled and uncontrolled at the same time. An input cannot switch between being controlled or uncontrolled over its lifetime. Every controlled input needs an onChange event handler that synchronously updates its backing value.
input component basic rendering
The <input> component renders the built-in browser input element. By default it creates a text input. You can specify different types using the type prop, such as type="checkbox" for a checkbox, type="radio" for a radio button, or one of the other standard HTML input types.
input props for controlling value
To make an input controlled, pass one of these props: checked (boolean, for checkbox/radio inputs to control whether selected) or value (string, for text inputs to control the text content). When passing either prop, you must also pass an onChange handler that updates the value. For radio buttons, the value prop specifies the form data.
input props for uncontrolled initial values
For uncontrolled inputs, use defaultValue (string for text inputs) or defaultChecked (boolean for checkbox/radio inputs) to specify the initial value. These props are only relevant for uncontrolled inputs and do not make the input controlled.
input formAction prop behavior
formAction can be a string or function. When a URL string is passed, the form behaves like a standard HTML form. When a function is passed, it handles the form submission. This prop overrides the parent <form action> for type="submit" and type="image" inputs.
input common props list
Input accepts all common element props plus accept, alt, capture, autoComplete, autoFocus, dirname, disabled, form, formAction, formEnctype, formMethod, formNoValidate, formTarget, height, list, max, maxLength, min, minLength, multiple, name, onChange, onChangeCapture, onInput, onInputCapture, onInvalid, onInvalidCapture, onSelect, onSelectCapture, pattern, placeholder, readOnly, required, size, src, step, type, and width props.
input onChange event handler
onChange is an event handler function required for controlled inputs. It fires immediately when the input's value is changed by the user, for example on every keystroke. It behaves like the browser input event. The handler receives a synthetic event where e.target.value contains the new value for text inputs and e.target.checked contains the new boolean state for checkboxes.
input onSelect event handler behavior
onSelect is an event handler that fires after the selection inside the <input> changes. React extends the onSelect event to also fire for empty selection and on edits which may affect the selection.
input children prop
The <input> component does not accept children.
input controlled component requires onChange
If you render an input with value but no onChange handler, React will throw an error and treat the input as read-only. You must pass an onChange handler for controlled text inputs to update the state variable synchronously.
checkbox controlled component requires onChange
If you render a checkbox with checked but no onChange handler, React will throw an error and treat the checkbox as read-only. You must pass an onChange handler for controlled checkboxes to update the state variable synchronously.
checkbox onChange uses e.target.checked not e.target.value
For checkboxes in onChange handlers, read e.target.checked (boolean) rather than e.target.value to get the new checked state.
input caret jump problem with transformation
If you control an input and transform its value in the onChange handler (such as calling .toUpperCase()), the input caret will jump to the beginning on every keystroke. You must update the state variable synchronously to exactly e.target.value without transformation.
input caret jump problem with async update
If you control an input and update its state asynchronously in onChange (such as with setTimeout), the input caret will jump to the beginning on every keystroke. You must update the state synchronously during the onChange handler.
input controlled to uncontrolled switch error
If you provide a value prop to an input, it must remain a string throughout its lifetime. You cannot pass value={undefined} first and later pass value="some string" because React needs to know whether the component should be controlled or uncontrolled. A controlled component should always receive a string value, not null or undefined. If value comes from an API or state that might be null or undefined, set it to an empty string ('') initially or use value={someValue ?? ''}.
checkbox controlled to uncontrolled switch
If you pass checked to a checkbox, ensure it is always a boolean throughout the component lifetime. Do not switch between undefined and a boolean value, as this will cause React to treat the component as switching between controlled and uncontrolled.
input value prop must be string not undefined or null
The value prop passed to a controlled input should never be undefined or null. If you need the initial value to be empty, initialize the state variable to an empty string ('').
input read-only with value and no onChange
If you want an input to be read-only with a value prop but no onChange handler, add a readOnly prop to suppress the React error: <input value={something} readOnly={true} />.
checkbox read-only with checked and no onChange
If you want a checkbox to be read-only with a checked prop but no onChange handler, add a readOnly prop to suppress the React error: <input type="checkbox" checked={something} readOnly={true} />.
input form prop associates with form by id
The form prop accepts a string specifying the id of the <form> element this input belongs to. If omitted, the input belongs to the closest parent form element.
input name prop required for form submission
Give a name to every <input> element, for example <input name="firstName" />. The name value is used as a key in the form data when the form is submitted, for example {firstName: "Taylor"}.
input with label using nested label
Typically place every <input> inside a <label> tag to associate them. When the user clicks the label, the browser will automatically focus the input. This is also essential for accessibility as screen readers will announce the label caption when the user focuses the input.
input with label using htmlFor and id
If you cannot nest <input> into a <label>, associate them by passing the same ID to <input id> and <label htmlFor>. To avoid conflicts between multiple instances of a component, generate the ID with useId.
input performance optimization by extracting state
When using a controlled input that updates state on every keystroke, if the parent component containing the state re-renders a large tree, performance can suffer. To optimize, move the input state into its own separate component so that only the input component re-renders on each keystroke, not the entire page.
input performance optimization with useDeferredValue
If there is no way to avoid re-rendering a large component tree when using a controlled input, useDeferredValue lets you keep the controlled input responsive even in the middle of a large re-render.
form submission with FormData
To read form data on submit, add a <form onSubmit> handler that calls e.preventDefault() to stop the page reload. Then create FormData with new FormData(e.target) and either pass it directly as fetch body or convert to object with Object.fromEntries(formData.entries()).
button type submit default behavior
By default, a <button> inside a <form> without a type attribute will submit the form. To prevent unexpected form submissions, use <button type="button"> for buttons that should not submit, and explicitly use <button type="submit"> for buttons that should submit.
input example displaying different types
Example showing how to render text input, checkbox, and radio buttons:
```js
export default function MyForm() {
return (
<>
<label>
Text input: <input name="myInput" />
</label>
<hr />
<label>
Checkbox: <input type="checkbox" name="myCheckbox" />
</label>
<hr />
<p>
Radio buttons:
<label>
<input type="radio" name="myRadio" value="option1" />
Option 1
</label>
<label>
<input type="radio" name="myRadio" value="option2" />
Option 2
</label>
<label>
<input type="radio" name="myRadio" value="option3" />
Option 3
</label>
</p>
</>
);
}
```
input example with initial values
Example showing how to provide initial values using defaultValue and defaultChecked:
```js
export default function MyForm() {
return (
<>
<label>
Text input: <input name="myInput" defaultValue="Some initial value" />
</label>
<hr />
<label>
Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} />
</label>
<hr />
<p>
Radio buttons:
<label>
<input type="radio" name="myRadio" value="option1" />
Option 1
</label>
<label>
<input
type="radio"
name="myRadio"
value="option2"
defaultChecked={true}
/>
Option 2
</label>
<label>
<input type="radio" name="myRadio" value="option3" />
Option 3
</label>
</p>
</>
);
}
```
input example controlled with state
Example showing a controlled input using useState:
```js
import { useState } from 'react';
export default function Form() {
const [firstName, setFirstName] = useState('');
const [age, setAge] = useState('20');
const ageAsNumber = Number(age);
return (
<>
<label>
First name:
<input
value={firstName}
onChange={e => setFirstName(e.target.value)}
/>
</label>
<label>
Age:
<input
value={age}
onChange={e => setAge(e.target.value)}
type="number"
/>
<button onClick={() => setAge(ageAsNumber + 10)}>
Add 10 years
</button>
</label>
{firstName !== '' &&
<p>Your name is {firstName}.</p>
}
{ageAsNumber > 0 &&
<p>Your age is {ageAsNumber}.</p>
}
</>
);
}
```
input example form submission with FormData
Example showing how to handle form submission and read input values:
```js
export default function MyForm() {
function handleSubmit(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
fetch('/some-api', { method: form.method, body: formData });
const formJson = Object.fromEntries(formData.entries());
console.log(formJson);
}
return (
<form method="post" onSubmit={handleSubmit}>
<label>
Text input: <input name="myInput" defaultValue="Some initial value" />
</label>
<hr />
<label>
Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} />
</label>
<hr />
<p>
Radio buttons:
<label><input type="radio" name="myRadio" value="option1" /> Option 1</label>
<label><input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Option 2</label>
<label><input type="radio" name="myRadio" value="option3" /> Option 3</label>
</p>
<hr />
<button type="reset">Reset form</button>
<button type="submit">Submit form</button>
</form>
);
}
```
input example with label and useId
Example showing how to use useId to generate unique IDs for label and input association:
```js
import { useId } from 'react';
export default function Form() {
const ageInputId = useId();
return (
<>
<label>
Your first name:
<input name="firstName" />
</label>
<hr />
<label htmlFor={ageInputId}>Your age:</label>
<input id={ageInputId} name="age" type="number" />
</>
);
}
```
<option> component for select box
The <option> component is a built-in browser component that renders an option inside a <select> box. It is used to provide selectable options within a select form control.
Select box with options example
Example showing how to render a select box with option elements:
```js
export default function FruitPicker() {
return (
<label>
Pick a fruit:
<select name="selectedFruit">
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="orange">Orange</option>
</select>
</label>
);
}
```
This example shows a select box with three fruit options, each having a value attribute used for form submission.
<option> common element props
The <option> component supports all common element props in addition to its specific props (disabled, label, and value).
<option> does not support selected attribute
React does not support the selected attribute on <option>. Instead, control selection by passing the option's value to the parent <select defaultValue> prop for uncontrolled select boxes, or to the <select value> prop for controlled select boxes.
<option> disabled prop
The disabled prop is a boolean that makes an option non-selectable when true. When disabled, the option appears dimmed to the user.