Skip to content

Commit 5c5e34a

Browse files
authored
fix(material/form-field): fix duplicate announcement of form controls (#27102)
Fix duplicate screen reader announcement of form controls. Remove the aria-owns from the form label. Commit 4191b4d added aria-owns on the label to work around issue in JAWS and NVDA. That commit is from 2017, and it appears the JAWS and NVDA issues have been fixed. Tested on NVDA, JAWS and VoiceOver by verifying that I am able to read the form field's label using screen reader. Tested on both Windows and Firefox. Testing environment: - Windows 10 Enterprise Version 22H2 - Chrome Version 114.0.5735.199 (Official Build) (64-bit) - Firefox 115.0 (64-bit) - NVDA version 2022.3 - JAWS Verison 2020.2006.12 ILM - MacOS 13.4.1 (22F82) - VoiceOver - Chrome Version 114.0.5735.198 (Official Build) (arm64) - Firefox Version 114.0.2 (64-bit) Fix #26583
1 parent ffffc82 commit 5c5e34a

File tree

4 files changed

+1
-40
lines changed

4 files changed

+1
-40
lines changed

src/material/chips/chip-grid.spec.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -526,17 +526,6 @@ describe('MDC-based MatChipGrid', () => {
526526
expect(spy).toHaveBeenCalled();
527527
subscription.unsubscribe();
528528
});
529-
530-
it('should point the label id to the chip input', () => {
531-
const label = fixture.nativeElement.querySelector('label');
532-
const input = fixture.nativeElement.querySelector('input');
533-
534-
fixture.detectChanges();
535-
536-
expect(label.getAttribute('for')).toBeTruthy();
537-
expect(label.getAttribute('for')).toBe(input.getAttribute('id'));
538-
expect(label.getAttribute('aria-owns')).toBe(input.getAttribute('id'));
539-
});
540529
});
541530

542531
describe('with chip remove', () => {

src/material/datepicker/date-range-input.spec.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,6 @@ describe('MatDateRangeInput', () => {
161161
expect(rangeInput.classList).toContain(hideClass);
162162
});
163163

164-
it('should point the label aria-owns to the <mat-date-range-input/>', () => {
165-
const fixture = createComponent(StandardRangePicker);
166-
fixture.detectChanges();
167-
const label = fixture.nativeElement.querySelector('label');
168-
const rangeInput = fixture.componentInstance.rangeInput;
169-
170-
expect(rangeInput.id).toBeTruthy();
171-
expect(label.getAttribute('aria-owns')).toBe(rangeInput.id);
172-
});
173-
174164
it('should point the range input aria-labelledby to the form field label', () => {
175165
const fixture = createComponent(StandardRangePicker);
176166
fixture.detectChanges();

src/material/form-field/form-field.html

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,13 @@
1010
as part of the label, and we don't want to spend resources on walking through projected content
1111
to set `aria-hidden`. Nor do we want to set `aria-labelledby` on every form control if we could
1212
simply link the label to the control using the label `for` attribute.
13-
14-
*Note*: We add aria-owns as a workaround for an issue in JAWS & NVDA where the label isn't
15-
read if it comes before the control in the DOM.
1613
-->
1714
<label matFormFieldFloatingLabel
1815
[floating]="_shouldLabelFloat()"
1916
[monitorResize]="_hasOutline()"
2017
*ngIf="_hasFloatingLabel()"
2118
[id]="_labelId"
22-
[attr.for]="_control.id"
23-
[attr.aria-owns]="_control.id">
19+
[attr.for]="_control.id">
2420
<ng-content select="mat-label"></ng-content>
2521
<!--
2622
We set the required marker as a separate element, in order to make it easier to target if

src/material/input/input.spec.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -188,20 +188,6 @@ describe('MatMdcInput without forms', () => {
188188
expect(inputElement.id).toEqual(labelElement.getAttribute('for')!);
189189
}));
190190

191-
it('should add aria-owns to the label for the associated control', fakeAsync(() => {
192-
let fixture = createComponent(MatInputTextTestController);
193-
fixture.detectChanges();
194-
195-
const inputElement: HTMLInputElement = fixture.debugElement.query(
196-
By.css('input'),
197-
)!.nativeElement;
198-
const labelElement: HTMLInputElement = fixture.debugElement.query(
199-
By.css('label'),
200-
)!.nativeElement;
201-
202-
expect(labelElement.getAttribute('aria-owns')).toBe(inputElement.id);
203-
}));
204-
205191
it('should add aria-required reflecting the required state', fakeAsync(() => {
206192
const fixture = createComponent(MatInputWithRequired);
207193
fixture.detectChanges();

0 commit comments

Comments
 (0)