> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/angular/angular/llms.txt
> Use this file to discover all available pages before exploring further.

# Validators

> API reference for Angular's Validators class, which provides a set of built-in validators for form controls.

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

```ts theme={null}
import { Validators } from '@angular/forms';
```

## Built-in Validators

### required

Validator that requires the control have a non-empty value.

```ts theme={null}
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
```

<ResponseField name="Returns" type="ValidationErrors | null">
  An error map with the `required` property if the validation check fails, otherwise `null`.
</ResponseField>

### requiredTrue

Validator that requires the control's value be true. This validator is commonly used for required checkboxes.

```ts theme={null}
const acceptTerms = new FormControl(false, Validators.requiredTrue);
console.log(acceptTerms.errors); // { required: true }

acceptTerms.setValue(true);
console.log(acceptTerms.errors); // null
```

<ResponseField name="Returns" type="ValidationErrors | null">
  An error map with the `required` property set to `true` if the validation check fails, otherwise `null`.
</ResponseField>

### 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

```ts theme={null}
const emailControl = new FormControl('', Validators.email);

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

emailControl.setValue('user@example.com');
console.log(emailControl.errors); // null
```

<ResponseField name="Returns" type="ValidationErrors | null">
  An error map with the `email` property if the validation check fails, otherwise `null`.
</ResponseField>

### min()

Validator that requires the control's value to be greater than or equal to the provided number.

<ParamField path="min" type="number" required>
  The minimum value.
</ParamField>

```ts theme={null}
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
```

<ResponseField name="Returns" type="ValidatorFn">
  A validator function that returns an error map with the `min` property if the validation check fails, otherwise `null`.
</ResponseField>

### max()

Validator that requires the control's value to be less than or equal to the provided number.

<ParamField path="max" type="number" required>
  The maximum value.
</ParamField>

```ts theme={null}
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
```

<ResponseField name="Returns" type="ValidatorFn">
  A validator function that returns an error map with the `max` property if the validation check fails, otherwise `null`.
</ResponseField>

### 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.

<ParamField path="minLength" type="number" required>
  The minimum length.
</ParamField>

```ts theme={null}
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
```

```html theme={null}
<!-- Also available as HTML attribute -->
<input minlength="5">
```

<ResponseField name="Returns" type="ValidatorFn">
  A validator function that returns an error map with the `minlength` property if the validation check fails, otherwise `null`.
</ResponseField>

### 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.

<ParamField path="maxLength" type="number" required>
  The maximum length.
</ParamField>

```ts theme={null}
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
```

```html theme={null}
<!-- Also available as HTML attribute -->
<input maxlength="10">
```

<ResponseField name="Returns" type="ValidatorFn">
  A validator function that returns an error map with the `maxlength` property if the validation check fails, otherwise `null`.
</ResponseField>

### pattern()

Validator that requires the control's value to match a regex pattern.

<ParamField path="pattern" type="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).
</ParamField>

```ts theme={null}
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
```

```html theme={null}
<!-- Also available as HTML attribute -->
<input pattern="[a-zA-Z ]*">
```

<Warning>
  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.
</Warning>

```ts theme={null}
// Not recommended (uses global flag)
const control1 = new FormControl('1', Validators.pattern(/foo/g));

// Good
const control2 = new FormControl('1', Validators.pattern(/foo/));
```

<ResponseField name="Returns" type="ValidatorFn">
  A validator function that returns an error map with the `pattern` property if the validation check fails, otherwise `null`.
</ResponseField>

### nullValidator()

Validator that performs no operation.

```ts theme={null}
const control = new FormControl('', Validators.nullValidator);
console.log(control.errors); // null
```

<ResponseField name="Returns" type="ValidationErrors | null">
  Always returns `null`.
</ResponseField>

## Composing Validators

### compose()

Composes multiple validators into a single function that returns the union of the individual error maps.

<ParamField path="validators" type="(ValidatorFn | null | undefined)[]" required>
  An array of validator functions to compose.
</ParamField>

```ts theme={null}
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);
```

<ResponseField name="Returns" type="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`.
</ResponseField>

### composeAsync()

Composes multiple async validators into a single function that returns the union of the individual error objects.

<ParamField path="validators" type="(AsyncValidatorFn | null)[]" required>
  An array of async validator functions to compose.
</ParamField>

```ts theme={null}
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
});
```

<ResponseField name="Returns" type="AsyncValidatorFn | null">
  A validator function that returns an error map with the merged error objects if the validation check fails, otherwise `null`.
</ResponseField>

## Using Multiple Validators

You can apply multiple validators to a single control:

```ts theme={null}
const control = new FormControl('', [
  Validators.required,
  Validators.minLength(3),
  Validators.maxLength(20),
  Validators.pattern(/^[a-zA-Z0-9]+$/)
]);
```

Or using the options object:

```ts theme={null}
const control = new FormControl('', {
  validators: [
    Validators.required,
    Validators.email
  ],
  asyncValidators: customAsyncValidator,
  updateOn: 'blur'
});
```

## Custom Validators

### Creating a Custom Validator

```ts theme={null}
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

```ts theme={null}
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

```ts theme={null}
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:

```ts theme={null}
type ValidationErrors = {
  [key: string]: any;
};
```

### Checking for Specific Errors

```ts theme={null}
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:

```ts theme={null}
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:

```ts theme={null}
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;
  }
}
```

```html theme={null}
<input type="text" name="username" ngModel appForbiddenName>
```

## Validation Timing

Control when validation occurs using `updateOn`:

```ts theme={null}
// 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.

```ts theme={null}
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.

```ts theme={null}
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

* [FormControl](/api/forms/form-control) - Apply validators to individual controls
* [FormGroup](/api/forms/form-group) - Group-level validation
* [Form Validation Guide](https://angular.dev/forms/overview/form-validation)
* [Custom Validators Guide](https://angular.dev/forms/overview/form-validation#defining-custom-validators)
