How to Validate Password and Confirm Password in Angular Forms

One thing we often need in user forms — especially during signup — is to make sure two fields match. Like confirming a password. Angular gives us built-in validators like required, minLength, and pattern, but when we need to compare fields, we’ve got to go custom.

Here’s how I handle that by creating a reusable validator directive that checks if two fields in a form are equal.


🔧 The Custom Directive: EqualValidator

This directive is flexible and works with both template-driven and reactive forms.

Here’s the code:

import { Directive, forwardRef, Attribute } from '@angular/core';
import { Validator, FormControl, NG_VALIDATORS } from '@angular/forms';

@Directive({
selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true },
]
})
export class EqualValidator implements Validator {
constructor(
@Attribute('validateEqual') public validateEqual: string,
@Attribute('reverse') public reverse: string
) {}

private get isReverse(): boolean {
return this.reverse === 'true';
}

validate(control: FormControl): { [key: string]: any } | null {
const currentValue = control.value;
const targetControl = control.root.get(this.validateEqual);

if (!targetControl) return null;

// Normal direction: this control must match the target
if (!this.isReverse && currentValue !== targetControl.value) {
return { validateEqual: false };
}

// Reverse direction: update the other field's validity
if (this.isReverse) {
if (currentValue === targetControl.value) {
if (targetControl.errors?.['validateEqual']) {
delete targetControl.errors['validateEqual'];
if (!Object.keys(targetControl.errors).length) {
targetControl.setErrors(null);
}
}
} else {
targetControl.setErrors({ validateEqual: false });
}
}

return null;
}
}

🤔 What’s Going On Here?

  • validateEqual="password" tells the directive which control to compare with.
  • reverse="true" is used on the second input (e.g., confirm password) so we can re-trigger validation when it changes.
  • The logic compares values and either adds or clears validation errors.

🧪 How I Use It in a Form

HTML Template:

<form [formGroup]="registerForm">
<input type="password" formControlName="password" placeholder="Password" />
<input
type="password"
formControlName="confirmPassword"
validateEqual="password"
reverse="true"
placeholder="Confirm Password"
/>
<button type="submit" [disabled]="!registerForm.valid">Register</button>
</form>

Component:

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
selector: 'app-register',
templateUrl: './register.component.html'
})
export class RegisterComponent {
registerForm: FormGroup;

constructor(private fb: FormBuilder) {
this.registerForm = this.fb.group({
password: ['', [Validators.required, Validators.minLength(6)]],
confirmPassword: ['', Validators.required]
});
}
}

🏁 Final Thoughts

This directive has been super helpful for me when working with forms that require field matching. It’s clean, reusable, and fits into Angular’s validation system perfectly.

Why I like this approach:

  • ✅ Works with reactive and template-driven forms.
  • ✅ Keeps templates clean — no need for extra conditional checks.
  • ✅ Easily reused in any form that needs field comparison (not just passwords!).

If you’re building forms in Angular and want an easy way to ensure two fields match — like passwords, emails, or even security questions — give this custom validator a shot. It works like a charm 💪

Let me know if you’d like a version with error messages or error styling included!

Leave a Comment

Your email address will not be published. Required fields are marked *