Skip to content
FLAVIO COPES
flaviocopes.com
2026

Form Actions

By Flavio Copes

Learn how React form actions simplify handling form submissions by passing the FormData object straight to your action, with no onSubmit handler or refs.

~~~

Within a component you might need to respond to an event (for example a click) with an event handler that must trigger something on the server.

Very common pattern:

import { useState } from 'react'

export const Demo = () => {
  const [fullName, setFullName] = useState('')

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()

    await fetch('<https://api.example.com/submit>', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ fullName }),
    })
  }

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type='text'
          value={fullName}
          onChange={(e) => setFullName(e.target.value)}
        />
        <button type='submit'>Submit</button>
      </form>
    </div>
  )
}

Same example, using FormData, which removes the need to track each individual input field value using a state management tool (useState in the above example):

import { useRef } from 'react'

export const Demo = () => {
  const formRef = useRef<HTMLFormElement>(null)

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()

    if (formRef.current) {
      const formData = new FormData(formRef.current)

      await fetch('<https://api.example.com/submit>', {
        method: 'POST',
        body: formData,
      })
    }
  }

  return (
    <div>
      <form ref={formRef} onSubmit={handleSubmit}>
        <input
          type='text'
          name='fullName'
        />
        <button type='submit'>Submit</button>
      </form>
    </div>
  )
}

The same thing now can be performed using an action:

export const Demo = () => {
  async function myFormAction(formData) => {
    await fetch('https://api.example.com/submit', {
      method: 'POST',
      body: formData,
    })
  }

  return (
    <div>
      <form action={myFormAction}>
        <input
          type='text'
          name='fullName'
        />
        <button type='submit'>Submit</button>
      </form>
    </div>
  )
}

Look how much simpler the code is, because now we don’t track the individual input fields state, but also we don’t respond to a browser event directly, and we don’t have to pass the form ref around to keep track of how to access it, because the actions is directly passed the FormData object.

Tagged: React · All topics
~~~

Related posts about react: