Build an Angular Email Form with Reactive Forms
Show email errors after interaction and prevent submission of an invalid form.
You are reading a translated version.
A subscription form needs more than an input. Users should understand why their data cannot be submitted. Reactive Forms keeps values and validation rules in a TypeScript form model.
This example uses one email control. Errors appear after interaction, and an invalid submission marks the control as touched. The example ends with local confirmation and does not send data to a subscription service.
Implementation example
import { Component, signal } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-subscribe',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form (ngSubmit)="submit()">
<label for="email">Email</label>
<input id="email" type="email" [formControl]="email"
aria-describedby="email-error" />
<p id="email-error" aria-live="polite">
@if (email.touched && email.invalid) { Enter a valid email. }
</p>
<button type="submit">Subscribe</button>
</form>
<p role="status">{{ message() }}</p>
`,
})
export class Subscribe {
email = new FormControl('', {
nonNullable: true,
validators: [Validators.required, Validators.email],
});
message = signal('');
submit(): void {
this.message.set('');
this.email.markAsTouched();
if (this.email.invalid) return;
this.message.set('Email format accepted. No request has been sent.');
}
}
Check the result
Submit an empty form, enter text without an email format, then try reader@example.com. The first two attempts should show an error. The final attempt displays a message without reloading the page.
The nonNullable option keeps the control value typed as a string, including after reset. A real application must validate on the server and display server-side errors. Correct email syntax does not prove that an address exists or belongs to the user.
