I´m working on this form and want to validate while typing. The current behavior it´s that I select the input, type and when I click on other site then the error it´s showing. I think the error it's happening when i set control, valid and dirty, but i can't figure it out. Typescript buildForm(): void { this.userForm = this.fb.group({ 'email': ['', [ Validators.required, Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$') ] ], 'password': ['', [ Validators.required, Validators.minLength(6), Validators.maxLength(25) ] ], }); this.userForm.valueChanges.subscribe(data => this.onValueChanged(data)); } onValueChanged(data?: any) { if (!this.userForm) { return; } const form = this.userForm; for (const field in this.formErrors) { // clear previous error message (if any) this.formErrors[field] = ''; const control = form.get(field); if (control && control.invalid && control.dirty) { const messages = this.validationMessages[field]; for (const key in control.errors) { this.formErrors[field] += messages[key] + ' '; } } } } Function onValueChanged() change this object formErrors = { 'email': '', 'password': '' }; And this object has the validation messages. validationMessages = { 'email': { 'required': 'Email is required', 'pattern': 'Email is invalid' }, 'password': { 'required': 'Password is required', 'minlength': 'Debe tener 6 caracteres como mínimo', 'maxlength': 'Password cannot be more than 40 characters long.', } }; HTML <mat-form-field class="example-full-width"> <input matInput placeholder="Email" formControlName="email" required> <mat-error *ngIf="formErrors.email" align="start" class="form__error"> {{ formErrors.email }} </mat-error> </mat-form-field> <mat-form-field class="example-full-width"> <input matInput placeholder="Password" type="password" formControlName="password" required> <mat-error *ngIf="formErrors.password" align="start" class="form__error"> {{ formErrors.password }} </mat-error> </mat-form-field> Continue reading...