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
actionattribute, 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.
onSubmitalso fires when the user presses Enter in a text field; a button'sonClickdoesn't. - Buttons inside a form are
type="submit"by default. Any button without atypesubmits 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
fetchinstead.- When
Every form handled with an
onSubmithandler.- Use case
A login form that logs the entered values.
Code compare
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().
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]orngFormnever reloads. - Use
event.currentTarget, notevent.target, when you need the form element in TypeScript:currentTargetis typed asHTMLFormElement;targetis a genericEventTarget. - Angular templates use plain HTML attributes:
for,class.
Quick reference
| React | Angular |
|---|---|
<form onSubmit={handleSubmit}> | <form [formGroup]="form" (ngSubmit)="onSubmit()"> |
event.preventDefault() | Not needed |
htmlFor, className | for, class |
Button default type="submit" | Same (HTML behavior) |