LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 3418 min read

Reactive Forms

Build forms whose structure and validation are defined in the component class using FormGroup and FormControl.

What Are Reactive Forms?

Reactive forms define a form's entire structure — its fields and validators — explicitly in the component class, as a tree of FormControl and FormGroup objects. The template then simply binds to that pre-built model, rather than driving its creation.

FormControl and FormGroup

A FormControl represents a single field; a FormGroup combines several controls (or nested groups) into one structured object.

import { Component } from '@angular/core';
import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-signup',
standalone: true,
imports: [ReactiveFormsModule],
template: `...`,
})
export class SignupComponent {
signupForm = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required, Validators.minLength(8)]),
});
}

FormBuilder

FormBuilder is a small helper service that reduces the boilerplate of constructing FormGroup/FormControl trees by hand.

import { Component, inject } from '@angular/core';
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
@Component({ selector: 'app-signup', standalone: true, imports: [ReactiveFormsModule], template: `...` })
export class SignupComponent {
private fb = inject(FormBuilder);
signupForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
});
}

Binding the Form in a Template

formGroup binds the whole model to a <form>, and formControlName connects each input to its matching control by name — the template stays a thin, declarative layer over the class-defined model.

<form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
<input formControlName="email" />
<input formControlName="password" type="password" />
<button type="submit" [disabled]="signupForm.invalid">Sign Up</button>
</form>
onSubmit() {
if (this.signupForm.valid) {
console.log(this.signupForm.value);
}
}

Reading Form State

<input formControlName="email" />
<p *ngIf="signupForm.get('email')?.invalid && signupForm.get('email')?.touched">
Please enter a valid email.
</p>

Reactive vs Template-Driven

Template-DrivenReactive
Form model defined inThe template, via ngModelThe component class, explicitly
TestabilityHarder — tied to the DOMEasier — the model is plain TypeScript
Dynamic fieldsAwkwardStraightforward — add/remove controls programmatically
Recommended forSmall, simple formsAnything moderately complex or dynamic

FAQs

Yes, on a per-component basis — but avoid mixing both approaches within the same form, since they represent different underlying models.

Yes — any standalone component using formGroup/formControlName must import ReactiveFormsModule directly.

Summary

Reactive forms define the form model explicitly in the class, making them more testable and better suited to complex or dynamic forms. Next, you'll go deeper into validation, including custom and async validators.

Next Lesson →

Form Validation