Working with Forms & User InputEntry 1 of 10

Submitting a Form: onSubmit, preventDefault, and Button Types

A form's onSubmit handler runs when the form is submitted. Calling event.preventDefault() stops the browser's default behavior: sending an HTTP request and reloading the page.

Notes

By default, an HTML form:

  • Sends its data to the server (the URL in its action attribute, or the current page).
  • Reloads the page with the response.

In a single-page app, that reload throws away all React state. So the handler takes over:

  • Listen on the form, not the button. onSubmit also fires when the user presses Enter in a text field; a button's onClick doesn't.
  • Buttons inside a form are type="submit" by default. Any button without a type submits the form.
  • type="button" does nothing on its own; use it for Cancel, Show password, and other buttons that must not submit.
  • type="reset" clears the form to its default values (Entry 5).

JSX attribute names follow the DOM property names, not HTML: htmlFor instead of for, className instead of class.

What / Why / When

What

Taking control of form submission in JavaScript.

Why

Keep the single-page app alive and send the data with fetch instead.

When

Every form handled with an onSubmit handler.

Use case

A login form that logs the entered values.

Code compare

React
import type { FormEvent } from "react";​export default function Login() {  function handleSubmit(event: FormEvent<HTMLFormElement>) {    event.preventDefault(); // no HTTP request, no page reload    console.log("Submitted!");  }​  return (    <form onSubmit={handleSubmit}>      <h2>Login</h2>​      <div className="control">        <label htmlFor="email">Email</label>        <input id="email" type="email" name="email" />      </div>​      <div className="control">        <label htmlFor="password">Password</label>        <input id="password" type="password" name="password" />      </div>​      <p className="form-actions">        <button type="reset" className="button button-flat">          Reset        </button>        <button type="submit" className="button">          Login        </button>      </p>    </form>  );}

Angular's forms module handles the submit event for you: (ngSubmit) fires on submit and the page doesn't reload, so there's no preventDefault().

Angular
import { Component } from "@angular/core";import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms";​@Component({  selector: "app-login",  imports: [ReactiveFormsModule],  template: `    <form [formGroup]="form" (ngSubmit)="onSubmit()">      <h2>Login</h2>​      <div class="control">        <label for="email">Email</label>        <input id="email" type="email" formControlName="email" />      </div>​      <div class="control">        <label for="password">Password</label>        <input id="password" type="password" formControlName="password" />      </div>​      <p class="form-actions">        <button type="reset" class="button button-flat">Reset</button>        <button type="submit" class="button">Login</button>      </p>    </form>  `,})export class LoginComponent {  form = new FormGroup({    email: new FormControl("", { nonNullable: true }),    password: new FormControl("", { nonNullable: true }),  });​  onSubmit() {    console.log("Submitted!", this.form.getRawValue());  }}

Differences and gotchas

  • In React, forgetting preventDefault() reloads the page and loses all state. In Angular, a form with [formGroup] or ngForm never reloads.
  • Use event.currentTarget, not event.target, when you need the form element in TypeScript: currentTarget is typed as HTMLFormElement; target is a generic EventTarget.
  • Angular templates use plain HTML attributes: for, class.

Quick reference

ReactAngular
<form onSubmit={handleSubmit}><form [formGroup]="form" (ngSubmit)="onSubmit()">
event.preventDefault()Not needed
htmlFor, classNamefor, class
Button default type="submit"Same (HTML behavior)