Forms: Form Actions

Join the AI Workshop to learn more about AI and how it can be applied to web development. Next cohort February 1st, 2026

The AI-first Web Development BOOTCAMP cohort starts February 24th, 2026. 10 weeks of intensive training and hands-on projects.


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.

Lessons in this unit:

0: Introduction
1: Managing forms in React
2: ▶︎ Form Actions
3: React, how to make a checked checkbox editable
4: How I fixed an issue with a React login form state and Browser autofill
5: How to get the value of an input element in React