Form state tracking helps you know if a user has changed or interacted with a form field and if the input is valid. This makes forms smarter and friendlier.
0
0
Form state tracking (dirty, touched, valid) in Angular
Introduction
When you want to show error messages only after a user has touched a field.
When you want to enable a submit button only if the form is valid and changed.
When you want to reset the form state after submission.
When you want to highlight fields that need attention based on user interaction.
Syntax
Angular
import { Component } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; @Component({ standalone: true, selector: 'app-simple-form', template: ` <input [formControl]="nameControl" aria-label="Name input" /> <div *ngIf="nameControl.touched && nameControl.invalid" role="alert"> Name is required. </div> <button [disabled]="!nameControl.dirty || nameControl.invalid">Submit</button> ` }) export class SimpleFormComponent { nameControl = new FormControl('', Validators.required); }
dirty means the user changed the value from the original.
touched means the user focused and then left the field.
valid means the current value passes all validation rules.
Examples
True if the user changed the input value.
Angular
nameControl.dirty
True if the user focused and then blurred the input.
Angular
nameControl.touched
True if the input value meets all validators.
Angular
nameControl.valid
True if the input value fails any validator.
Angular
nameControl.invalid
Sample Program
This component tracks the state of an email input. It shows messages only after the user touches the field and if the email is invalid. The submit button is enabled only if the user changed the input and the email is valid.
Angular
import { Component } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; @Component({ standalone: true, selector: 'app-form-state', template: ` <label for="email">Email:</label> <input id="email" type="email" [formControl]="emailControl" aria-describedby="emailHelp" [attr.aria-invalid]="emailControl.invalid" /> <div id="emailHelp" *ngIf="emailControl.touched && emailControl.invalid" role="alert" style="color: red;"> Please enter a valid email. </div> <p>Dirty: {{emailControl.dirty}}</p> <p>Touched: {{emailControl.touched}}</p> <p>Valid: {{emailControl.valid}}</p> <button [disabled]="!emailControl.dirty || emailControl.invalid">Submit</button> ` }) export class FormStateComponent { emailControl = new FormControl('', [Validators.required, Validators.email]); }
OutputSuccess
Important Notes
Use touched to avoid showing errors before the user interacts.
dirty helps to detect if the user made changes to the form.
Always combine these states to improve user experience in forms.
Summary
dirty means the user changed the input value.
touched means the user focused and left the input.
valid means the input passes validation rules.