<form>This feature is available in the latest Canary

Canary

React’s form Component is currently only available in React’s canary and experimental channels but you can use the standard HTML form tag in your React’s stable channel. Learn more about React’s release channels here.

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>

See more examples below.

🚧 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>’s action 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} />;
}

Pitfall

The useFormStatus Hook must be called from a Component that is located inside <form>. You cannot call useFormStatus from the same Component that returns <form>.

function Form() {
const { pending } = useFormStatus() // 🚩 `pending` will never be `true`
return <form action={submit}> //...
}

Instead call useFormStatus from inside a Component that is located inside <form>.

function Button(){
const { pending } = useFormStatus() // ✅ `pending` will be derived from the parent form state
return <button disabled={pending}> //...
}

function Form() {
return <form> <Button /> //...
}

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>
  );
}