Skip to content

Commit 0028b74

Browse files
fix(material/input): Do not set aria-invalid on empty matInputs
Updates the logic for setting `aria-invalid` on `matInput` to not set the value at all if the input has no value. Prior to this PR `matInput` sets `aria-invalid="false"` for any empty `matInput`, including `required` ones. This suppresses screen readers' announcement to users that such inputs are in an invalid state. Fixes #22777 Add MDC implementation. Whoops.
1 parent 0a4dbe1 commit 0028b74

File tree

4 files changed

+10
-10
lines changed

4 files changed

+10
-10
lines changed

src/material-experimental/mdc-input/input.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,7 @@ describe('MatMdcInput with forms', () => {
928928
expect(testComponent.formControl.untouched).toBe(true, 'Expected untouched form control');
929929
expect(containerEl.querySelectorAll('mat-error').length).toBe(0, 'Expected no error message');
930930
expect(inputEl.getAttribute('aria-invalid'))
931-
.toBe('false', 'Expected aria-invalid to be set to "false".');
931+
.toBe(null, 'Expected aria-invalid not to be present.');
932932
}));
933933

934934
it('should display an error message when the input is touched and invalid', fakeAsync(() => {
@@ -997,7 +997,7 @@ describe('MatMdcInput with forms', () => {
997997
expect(component.formGroup.invalid).toBe(true, 'Expected form control to be invalid');
998998
expect(containerEl.querySelectorAll('mat-error').length).toBe(0, 'Expected no error message');
999999
expect(inputEl.getAttribute('aria-invalid'))
1000-
.toBe('false', 'Expected aria-invalid to be set to "false".');
1000+
.toBe(null, 'Expected aria-invalid not to be present');
10011001
expect(component.formGroupDirective.submitted)
10021002
.toBe(false, 'Expected form not to have been submitted');
10031003

@@ -1081,7 +1081,7 @@ describe('MatMdcInput with forms', () => {
10811081
expect(describedBy).toBe(errorIds);
10821082
}));
10831083

1084-
it('should not set `aria-invalid` to true if the input is empty', fakeAsync(() => {
1084+
it('should not set `aria-invalid` if the input is empty', fakeAsync(() => {
10851085
// Submit the form since it's the one that triggers the default error state matcher.
10861086
dispatchFakeEvent(fixture.nativeElement.querySelector('form'), 'submit');
10871087
fixture.detectChanges();
@@ -1090,7 +1090,7 @@ describe('MatMdcInput with forms', () => {
10901090
expect(testComponent.formControl.invalid).toBe(true, 'Expected form control to be invalid');
10911091
expect(inputEl.value).toBeFalsy();
10921092
expect(inputEl.getAttribute('aria-invalid'))
1093-
.toBe('false', 'Expected aria-invalid to be set to "false".');
1093+
.toBe(null, 'Expected aria-invalid not to be present');
10941094

10951095
inputEl.value = 'not valid';
10961096
fixture.detectChanges();

src/material-experimental/mdc-input/input.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import {MatInput as BaseMatInput} from '@angular/material/input';
3939
'[attr.readonly]': 'readonly && !_isNativeSelect || null',
4040
// Only mark the input as invalid for assistive technology if it has a value since the
4141
// state usually overlaps with `aria-required` when the input is empty and can be redundant.
42-
'[attr.aria-invalid]': 'errorState && !empty',
42+
'[attr.aria-invalid]': 'empty ? null : errorState',
4343
'[attr.aria-required]': 'required',
4444
},
4545
providers: [{provide: MatFormFieldControl, useExisting: MatInput}],

src/material/input/input.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,7 +1081,7 @@ describe('MatInput with forms', () => {
10811081
expect(testComponent.formControl.untouched).toBe(true, 'Expected untouched form control');
10821082
expect(containerEl.querySelectorAll('mat-error').length).toBe(0, 'Expected no error message');
10831083
expect(inputEl.getAttribute('aria-invalid'))
1084-
.toBe('false', 'Expected aria-invalid to be set to "false".');
1084+
.toBe(null, 'Expected aria-invalid not to be present.');
10851085
}));
10861086

10871087
it('should display an error message when the input is touched and invalid', fakeAsync(() => {
@@ -1135,7 +1135,7 @@ describe('MatInput with forms', () => {
11351135
expect(component.formGroup.invalid).toBe(true, 'Expected form control to be invalid');
11361136
expect(containerEl.querySelectorAll('mat-error').length).toBe(0, 'Expected no error message');
11371137
expect(inputEl.getAttribute('aria-invalid'))
1138-
.toBe('false', 'Expected aria-invalid to be set to "false".');
1138+
.toBe(null, 'Expected aria-invalid not to be present.');
11391139
expect(component.formGroupDirective.submitted)
11401140
.toBe(false, 'Expected form not to have been submitted');
11411141

@@ -1219,7 +1219,7 @@ describe('MatInput with forms', () => {
12191219
expect(describedBy).toBe(errorIds);
12201220
}));
12211221

1222-
it('should not set `aria-invalid` to true if the input is empty', fakeAsync(() => {
1222+
it('should not set `aria-invalid` if the input is empty', fakeAsync(() => {
12231223
// Submit the form since it's the one that triggers the default error state matcher.
12241224
dispatchFakeEvent(fixture.nativeElement.querySelector('form'), 'submit');
12251225
fixture.detectChanges();
@@ -1228,7 +1228,7 @@ describe('MatInput with forms', () => {
12281228
expect(testComponent.formControl.invalid).toBe(true, 'Expected form control to be invalid');
12291229
expect(inputEl.value).toBeFalsy();
12301230
expect(inputEl.getAttribute('aria-invalid'))
1231-
.toBe('false', 'Expected aria-invalid to be set to "false".');
1231+
.toBe(null, 'Expected aria-invalid not to be present.');
12321232

12331233
inputEl.value = 'not valid';
12341234
fixture.detectChanges();

src/material/input/input.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const _MatInputBase = mixinErrorState(class {
8383
'[attr.readonly]': 'readonly && !_isNativeSelect || null',
8484
// Only mark the input as invalid for assistive technology if it has a value since the
8585
// state usually overlaps with `aria-required` when the input is empty and can be redundant.
86-
'[attr.aria-invalid]': 'errorState && !empty',
86+
'[attr.aria-invalid]': 'empty ? null : errorState',
8787
'[attr.aria-required]': 'required',
8888
},
8989
providers: [{provide: MatFormFieldControl, useExisting: MatInput}],

0 commit comments

Comments
 (0)