Angular Forms
Forms
Angular forms are used to enable users to log in to the application, update a profile, enter sensitive information, and perform various data-entry tasks. In Angular 21, there are three approaches to building forms:
Reactive Forms
Using reactive forms, instead of defining the form in our template (i.e. in component.html), the structure of the form is defined in the component (i.e. component.ts).
Template-driven Forms
Using template-driven forms, we first create HTML input elements in the template and then use directives like ngModel to bind their value to a component's variable.
Signal Forms (Experimental - Angular 21)
Signal Forms are a new experimental approach via the @angular/forms/signals package, integrating deeply with Angular's Signals system for better type safety and simpler validation.
Both reactive and template-driven forms collect user input from the view, validate it, and track changes. For small projects, either approach works well. For larger projects, reactive forms are recommended as they scale better.
Reactive Forms Implementation (Angular 21 Standalone)
Step 1 - Generate the component
Create a component for reactive forms using the Angular CLI.
ng generate component reactive-form Step 2 - Import ReactiveFormsModule in the component
In Angular 21 standalone components, import ReactiveFormsModule directly in the component's imports array - no NgModule needed.
import { Component } from '@angular/core';import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';@Component({ selector: 'app-reactive-form', standalone: true, imports: [ReactiveFormsModule], template: ` <form [formGroup]="form" (ngSubmit)="onSubmit()"> <label> Name: <input formControlName="name" /> @if (form.get('name')?.invalid && form.get('name')?.touched) { <span style="color:red">Name is required</span> } </label> <br /> <label> Email: <input formControlName="email" type="email" /> @if (form.get('email')?.invalid && form.get('email')?.touched) { <span style="color:red">Valid email required</span> } </label> <br /> <button type="submit" [disabled]="form.invalid">Submit</button> </form> @if (submitted) { <p>Form submitted: {{ form.value | json }}</p> } `})export class ReactiveFormComponent { private fb = inject(FormBuilder); form = this.fb.group({ name: ['', Validators.required], email: ['', [Validators.required, Validators.email]] }); submitted = false; onSubmit() { if (this.form.valid) { this.submitted = true; } }}import { inject } from '@angular/core'; Template-driven Forms (Angular 21 Standalone)
Step 1 - Generate the component
ng generate component template-form Step 2 - Import FormsModule in the component
Import FormsModule directly in the standalone component's imports array to enable ngModel.
import { Component } from '@angular/core';import { FormsModule } from '@angular/forms';@Component({ selector: 'app-template-form', standalone: true, imports: [FormsModule], template: ` <form #f="ngForm" (ngSubmit)="onSubmit(f)"> <label> Name: <input name="name" ngModel required /> </label> <br /> <label> Email: <input name="email" ngModel required email type="email" /> </label> <br /> <button type="submit" [disabled]="f.invalid">Submit</button> </form> @if (result) { <p>Submitted: {{ result | json }}</p> } `})export class TemplateFormComponent { result: any; onSubmit(form: any) { this.result = form.value; }} Signal Forms (Angular 21 - Experimental)
Angular 21 introduces Signal Forms as an experimental new approach via the @angular/forms/signals package. Signal Forms integrate deeply with Angular's Signals system and provide better type safety and simpler validation compared to Reactive and Template-driven forms.