All topics
Formsadvanced

Cross-field Validation

Explain how to validate relationships between multiple sibling controls, like matching password confirmation fields.

Some validation rules can't be checked by looking at a single field in isolation — confirming two password fields match, ensuring an end date is after a start date, requiring at least one of several optional fields to be filled. Cross-field validation handles this by attaching a validator not to an individual FormControl, but to the parent FormGroup that contains all the related sibling controls, since only the group has access to every relevant control's current value at once.

It's like a wedding officiant who doesn't just check each ring individually for damage, but specifically confirms both rings actually fit the two people standing in front of them — a check that only makes sense when looking at both parties together, not either one alone.

Key Concepts

1
The validator function itself uses the exact same ValidatorFn signature as a single-control validator (it receives an AbstractControl and returns ValidationErrors | null) — the only difference is that when it's attached to a FormGroup, the AbstractControl it receives is the group itself, and the validator reaches into it via group.get('fieldName') to compare sibling values.
ValidatorFnAbstractControlValidationErrors | nullFormGroupgroup.get('fieldName')
2
A subtlety worth highlighting in an interview: a validation error produced by a group-level validator lives on the group's own errors object, not on any individual child control's errors — which affects how you display the error in the template (form.hasError('passwordMismatch') rather than form.get('confirmPassword')?.hasError(...)), and is a common point of confusion for developers used to only ever checking individual control errors.
errorsform.hasError('passwordMismatch')form.get('confirmPassword')?.hasError(...)
3
A well-designed cross-field validator also needs to re-run whenever any of the involved sibling controls changes, which happens automatically since Angular re-evaluates a FormGroup's own validators any time any descendant control's value changes — but it's worth explicitly mentioning that this means a validator comparing password and confirmPassword re-runs on every keystroke in either field, which is usually the desired behavior but worth being aware of for performance-sensitive forms.
FormGrouppasswordconfirmPassword