Skip to main content
The Validators class provides a set of built-in validators that can be used by form controls. A validator is a function that processes a FormControl or collection of controls and returns an error map or null. A null map means that validation has passed.

Import

import { Validators } from '@angular/forms';

Built-in Validators

required

Validator that requires the control have a non-empty value.
import { FormControl, Validators } from '@angular/forms';

const control = new FormControl('', Validators.required);
console.log(control.errors); // { required: true }

control.setValue('value');
console.log(control.errors); // null
Returns
ValidationErrors | null
An error map with the required property if the validation check fails, otherwise null.

requiredTrue

Validator that requires the control’s value be true. This validator is commonly used for required checkboxes.
const acceptTerms = new FormControl(false, Validators.requiredTrue);
console.log(acceptTerms.errors); // { required: true }

acceptTerms.setValue(true);
console.log(acceptTerms.errors); // null
Returns
ValidationErrors | null
An error map with the required property set to true if the validation check fails, otherwise null.

email

Validator that requires the control’s value pass an email validation test. The validator uses a regular expression pattern based on the WHATWG HTML specification with enhancements:
  • Disallows local-part to begin or end with a period (.)
  • Disallows local-part to be longer than 64 characters
  • Disallows the whole address to be longer than 254 characters
const emailControl = new FormControl('', Validators.email);

emailControl.setValue('invalid');
console.log(emailControl.errors); // { email: true }

emailControl.setValue('[email protected]');
console.log(emailControl.errors); // null
Returns
ValidationErrors | null
An error map with the email property if the validation check fails, otherwise null.

min()

Validator that requires the control’s value to be greater than or equal to the provided number.
min
number
required
The minimum value.
const ageControl = new FormControl(2, Validators.min(3));
console.log(ageControl.errors); // { min: { min: 3, actual: 2 } }

ageControl.setValue(5);
console.log(ageControl.errors); // null
Returns
ValidatorFn
A validator function that returns an error map with the min property if the validation check fails, otherwise null.

max()

Validator that requires the control’s value to be less than or equal to the provided number.
max
number
required
The maximum value.
const scoreControl = new FormControl(16, Validators.max(15));
console.log(scoreControl.errors); // { max: { max: 15, actual: 16 } }

scoreControl.setValue(10);
console.log(scoreControl.errors); // null
Returns
ValidatorFn
A validator function that returns an error map with the max property if the validation check fails, otherwise null.

minLength()

Validator that requires the number of items in the control’s value to be greater than or equal to the provided minimum length. This validator is intended for types that have a numeric length or size property, such as strings, arrays, or sets. The validator logic is not invoked for values when their length or size property is 0.
minLength
number
required
The minimum length.
const nameControl = new FormControl('ab', Validators.minLength(3));
console.log(nameControl.errors);
// { minlength: { requiredLength: 3, actualLength: 2 } }

nameControl.setValue('abc');
console.log(nameControl.errors); // null
<!-- Also available as HTML attribute -->
<input minlength="5">
Returns
ValidatorFn
A validator function that returns an error map with the minlength property if the validation check fails, otherwise null.

maxLength()

Validator that requires the number of items in the control’s value to be less than or equal to the provided maximum length. This validator is intended for types that have a numeric length or size property, such as strings, arrays, or sets.
maxLength
number
required
The maximum length.
const nameControl = new FormControl('Angular', Validators.maxLength(5));
console.log(nameControl.errors);
// { maxlength: { requiredLength: 5, actualLength: 7 } }

nameControl.setValue('Ng');
console.log(nameControl.errors); // null
<!-- Also available as HTML attribute -->
<input maxlength="10">
Returns
ValidatorFn
A validator function that returns an error map with the maxlength property if the validation check fails, otherwise null.

pattern()

Validator that requires the control’s value to match a regex pattern.
pattern
string | RegExp
required
A regular expression to test the values, or a string. If a string is passed, the ^ character is prepended and the $ character is appended (if not already present).
const codeControl = new FormControl('123', Validators.pattern('[a-zA-Z ]*'));
console.log(codeControl.errors);
// { pattern: { requiredPattern: '^[a-zA-Z ]*$', actualValue: '123' } }

codeControl.setValue('abc');
console.log(codeControl.errors); // null
<!-- Also available as HTML attribute -->
<input pattern="[a-zA-Z ]*">
Do not use the g (global) or y (sticky) flags with Validators.pattern(). These flags cause RegExp.prototype.test() to preserve the index of the last match, which can produce inconsistent results when validations run consecutively.
// Not recommended (uses global flag)
const control1 = new FormControl('1', Validators.pattern(/foo/g));

// Good
const control2 = new FormControl('1', Validators.pattern(/foo/));
Returns
ValidatorFn
A validator function that returns an error map with the pattern property if the validation check fails, otherwise null.

nullValidator()

Validator that performs no operation.
const control = new FormControl('', Validators.nullValidator);
console.log(control.errors); // null
Returns
ValidationErrors | null
Always returns null.

Composing Validators

compose()

Composes multiple validators into a single function that returns the union of the individual error maps.
validators
(ValidatorFn | null | undefined)[]
required
An array of validator functions to compose.
const passwordValidator = Validators.compose([
  Validators.required,
  Validators.minLength(8),
  Validators.pattern(/[A-Z]/), // Must contain uppercase
  Validators.pattern(/[0-9]/)  // Must contain number
]);

const passwordControl = new FormControl('', passwordValidator);
Returns
ValidatorFn | null
A validator function that returns an error map with the merged error maps of the validators if the validation check fails, otherwise null.

composeAsync()

Composes multiple async validators into a single function that returns the union of the individual error objects.
validators
(AsyncValidatorFn | null)[]
required
An array of async validator functions to compose.
import { AbstractControl, ValidationErrors } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { delay, map } from 'rxjs/operators';

function usernameValidator(control: AbstractControl): Observable<ValidationErrors | null> {
  return checkUsername(control.value).pipe(
    map(exists => exists ? { usernameTaken: true } : null)
  );
}

function emailValidator(control: AbstractControl): Observable<ValidationErrors | null> {
  return checkEmail(control.value).pipe(
    map(exists => exists ? { emailTaken: true } : null)
  );
}

const asyncValidator = Validators.composeAsync([
  usernameValidator,
  emailValidator
]);

const control = new FormControl('', {
  validators: Validators.required,
  asyncValidators: asyncValidator
});
Returns
AsyncValidatorFn | null
A validator function that returns an error map with the merged error objects if the validation check fails, otherwise null.

Using Multiple Validators

You can apply multiple validators to a single control:
const control = new FormControl('', [
  Validators.required,
  Validators.minLength(3),
  Validators.maxLength(20),
  Validators.pattern(/^[a-zA-Z0-9]+$/)
]);
Or using the options object:
const control = new FormControl('', {
  validators: [
    Validators.required,
    Validators.email
  ],
  asyncValidators: customAsyncValidator,
  updateOn: 'blur'
});

Custom Validators

Creating a Custom Validator

import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

function forbiddenNameValidator(forbiddenName: string): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const forbidden = control.value?.toLowerCase() === forbiddenName.toLowerCase();
    return forbidden ? { forbiddenName: { value: control.value } } : null;
  };
}

const nameControl = new FormControl('', [
  Validators.required,
  forbiddenNameValidator('admin')
]);

nameControl.setValue('admin');
console.log(nameControl.errors);
// { forbiddenName: { value: 'admin' } }

Custom Async Validator

import { AbstractControl, ValidationErrors, AsyncValidatorFn } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { map, catchError, debounceTime, switchMap } from 'rxjs/operators';

function uniqueUsernameValidator(userService: UserService): AsyncValidatorFn {
  return (control: AbstractControl): Observable<ValidationErrors | null> => {
    if (!control.value) {
      return of(null);
    }
    
    return of(control.value).pipe(
      debounceTime(500),
      switchMap(username => userService.checkUsername(username)),
      map(exists => exists ? { usernameTaken: true } : null),
      catchError(() => of(null))
    );
  };
}

const usernameControl = new FormControl('', {
  validators: [Validators.required, Validators.minLength(3)],
  asyncValidators: uniqueUsernameValidator(userService)
});

Cross-Field Validation

import { FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';

function passwordMatchValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const password = control.get('password');
    const confirmPassword = control.get('confirmPassword');
    
    if (!password || !confirmPassword) {
      return null;
    }
    
    return password.value === confirmPassword.value
      ? null
      : { passwordMismatch: true };
  };
}

const form = new FormGroup(
  {
    password: new FormControl('', [Validators.required, Validators.minLength(8)]),
    confirmPassword: new FormControl('', Validators.required)
  },
  { validators: passwordMatchValidator() }
);

console.log(form.errors); // { passwordMismatch: true } if passwords don't match

Validation Errors

Each validator returns a ValidationErrors object when validation fails:
type ValidationErrors = {
  [key: string]: any;
};

Checking for Specific Errors

const control = new FormControl('', [
  Validators.required,
  Validators.minLength(5)
]);

if (control.hasError('required')) {
  console.log('This field is required');
}

if (control.hasError('minlength')) {
  const error = control.getError('minlength');
  console.log(`Minimum length is ${error.requiredLength}, but got ${error.actualLength}`);
}

Dynamic Validators

You can add or remove validators dynamically:
const control = new FormControl('');

// Add validators
control.setValidators([Validators.required, Validators.email]);
control.updateValueAndValidity();

// Add more validators
control.addValidators(Validators.minLength(5));
control.updateValueAndValidity();

// Remove validators
control.removeValidators(Validators.required);
control.updateValueAndValidity();

// Clear all validators
control.clearValidators();
control.updateValueAndValidity();

Validator Directives

You can create custom validator directives for template-driven forms:
import { Directive } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl, ValidationErrors } from '@angular/forms';

@Directive({
  selector: '[appForbiddenName]',
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: ForbiddenNameDirective,
      multi: true
    }
  ]
})
export class ForbiddenNameDirective implements Validator {
  validate(control: AbstractControl): ValidationErrors | null {
    return control.value?.toLowerCase() === 'admin'
      ? { forbiddenName: true }
      : null;
  }
}
<input type="text" name="username" ngModel appForbiddenName>

Validation Timing

Control when validation occurs using updateOn:
// Validate on every change (default)
const control1 = new FormControl('', {
  validators: Validators.required,
  updateOn: 'change'
});

// Validate on blur
const control2 = new FormControl('', {
  validators: Validators.required,
  updateOn: 'blur'
});

// Validate on form submit
const control3 = new FormControl('', {
  validators: Validators.required,
  updateOn: 'submit'
});

Injection Tokens

NG_VALIDATORS

Injection token for registering additional synchronous validators.
import { NG_VALIDATORS } from '@angular/forms';

@Directive({
  selector: '[customValidator]',
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => CustomValidatorDirective),
      multi: true
    }
  ]
})
export class CustomValidatorDirective implements Validator {
  validate(control: AbstractControl): ValidationErrors | null {
    return { custom: true };
  }
}

NG_ASYNC_VALIDATORS

Injection token for registering additional asynchronous validators.
import { NG_ASYNC_VALIDATORS } from '@angular/forms';

@Directive({
  selector: '[customAsyncValidator]',
  providers: [
    {
      provide: NG_ASYNC_VALIDATORS,
      useExisting: CustomAsyncValidatorDirective,
      multi: true
    }
  ]
})
export class CustomAsyncValidatorDirective implements AsyncValidator {
  validate(control: AbstractControl): Observable<ValidationErrors | null> {
    return of({ custom: true }).pipe(delay(1000));
  }
}

See Also

Build docs developers (and LLMs) love