Handling Forms via Form ActionsEntry 1 of 10
Form Actions: <form action={fn}>
In React 19, a form's action prop can be a function. React calls it with the form's FormData when the form is submitted.
react.dev<form>
Notes
- No
onSubmit, noevent.preventDefault(), nonew FormData(...): React prevents the page reload and builds theFormDatafor you. - Every input still needs a
name; that's howFormDatafinds its value. - Read values with
formData.get('email')andformData.getAll('acquisition')(Working with Forms, Entry 4). - The function can be sync or async. React runs it inside a Transition, which is what makes pending state (Entry 5) and optimistic updates (Entry 8) possible.
- In plain HTML,
actionis a URL string. React only treats it differently when you pass a function.
What / Why / When
- What
A submit handler that receives
FormDatadirectly.- Why
Less boilerplate, and it unlocks
useActionState,useFormStatus, anduseOptimistic.- When
Forms you only need to read on submit (uncontrolled inputs).
- Use case
A signup form that logs the entered email.
Code compare
export default function Signup() { function signupAction(formData: FormData) { const enteredEmail = formData.get("email"); console.log(enteredEmail); } return ( <form action={signupAction}> <h2>Welcome on board!</h2> <p>We just need a little bit of data from you to get you started.</p> <div className="control"> <label htmlFor="email">Email</label> <input id="email" type="email" name="email" /> </div> <button type="submit">Sign up</button> </form> );}Angular has no action functions. The equivalent is (ngSubmit) with a Reactive Form; the values come from the form model instead of FormData.
@Component({ selector: "app-signup", imports: [ReactiveFormsModule], template: ` <form [formGroup]="form" (ngSubmit)="signup()"> <h2>Welcome on board!</h2> <label for="email">Email</label> <input id="email" type="email" formControlName="email" /> <button type="submit">Sign up</button> </form> `,})export class SignupComponent { form = new FormGroup({ email: new FormControl("", { nonNullable: true }), }); signup() { console.log(this.form.controls.email.value); }}Differences and gotchas
formData.get()returnsFormDataEntryValue | null(string | File | null). In TypeScript, convert before using:String(formData.get('email') ?? '').- A form action also works with
<button formAction={fn}>(Entry 7).
Quick reference
| React 19 | Angular |
|---|---|
<form action={signupAction}> | <form [formGroup] (ngSubmit)="signup()"> |
formData.get('email') | form.controls.email.value |
No preventDefault() | No preventDefault() |