diff --git a/src/material/chips/chip-listbox.spec.ts b/src/material/chips/chip-listbox.spec.ts index 81da833c51dd..0ce94118162d 100644 --- a/src/material/chips/chip-listbox.spec.ts +++ b/src/material/chips/chip-listbox.spec.ts @@ -513,19 +513,19 @@ describe('MDC-based MatChipListbox', () => { '.mdc-evolution-chip__action--primary', ); - expect(getAriaSelected()).toEqual([null, null, null]); + expect(getAriaSelected()).toEqual(['false', 'false', 'false']); primaryActions[1].click(); fixture.detectChanges(); - expect(getAriaSelected()).toEqual([null, 'true', null]); + expect(getAriaSelected()).toEqual(['false', 'true', 'false']); primaryActions[2].click(); fixture.detectChanges(); - expect(getAriaSelected()).toEqual([null, null, 'true']); + expect(getAriaSelected()).toEqual(['false', 'false', 'true']); primaryActions[0].click(); fixture.detectChanges(); - expect(getAriaSelected()).toEqual(['true', null, null]); + expect(getAriaSelected()).toEqual(['true', 'false', 'false']); })); it('should set `aria-selected` based on the selection state in multi-selection mode', fakeAsync(() => { @@ -548,15 +548,15 @@ describe('MDC-based MatChipListbox', () => { '.mdc-evolution-chip__action--primary', ); - expect(getAriaSelected()).toEqual([null, null, null]); + expect(getAriaSelected()).toEqual(['false', 'false', 'false']); primaryActions[1].click(); fixture.detectChanges(); - expect(getAriaSelected()).toEqual([null, 'true', null]); + expect(getAriaSelected()).toEqual(['false', 'true', 'false']); primaryActions[2].click(); fixture.detectChanges(); - expect(getAriaSelected()).toEqual([null, 'true', 'true']); + expect(getAriaSelected()).toEqual(['false', 'true', 'true']); primaryActions[0].click(); fixture.detectChanges(); @@ -564,7 +564,7 @@ describe('MDC-based MatChipListbox', () => { primaryActions[1].click(); fixture.detectChanges(); - expect(getAriaSelected()).toEqual(['true', null, 'true']); + expect(getAriaSelected()).toEqual(['true', 'false', 'true']); })); }); diff --git a/src/material/chips/chip-option.spec.ts b/src/material/chips/chip-option.spec.ts index bb5d1c2219e0..fed7f7eb4213 100644 --- a/src/material/chips/chip-option.spec.ts +++ b/src/material/chips/chip-option.spec.ts @@ -233,7 +233,7 @@ describe('MDC-based Option Chips', () => { }); it('should have correct aria-selected in single selection mode', () => { - expect(primaryAction.hasAttribute('aria-selected')).toBe(false); + expect(primaryAction.getAttribute('aria-selected')).toBe('false'); testComponent.selected = true; fixture.detectChanges(); diff --git a/src/material/chips/chip-option.ts b/src/material/chips/chip-option.ts index 4a7c48d5306a..f71c042e225c 100644 --- a/src/material/chips/chip-option.ts +++ b/src/material/chips/chip-option.ts @@ -106,13 +106,21 @@ export class MatChipOption extends MatChip implements OnInit { } private _selected = false; - /** The ARIA selected applied to the chip. */ + /** + * The ARIA selected applied to the chip. Conforms to WAI ARIA best practices for listbox + * interaction patterns. + * + * From [WAI ARIA Listbox authoring practices guide]( + * https://www.w3.org/WAI/ARIA/apg/patterns/listbox/): + * "If any options are selected, each selected option has either aria-selected or aria-checked + * set to true. All options that are selectable but not selected have either aria-selected or + * aria-checked set to false." + * + * Set `aria-selected="false"` on not-selected listbox options that are selectable to fix + * VoiceOver reading every option as "selected" (#25736). + */ get ariaSelected(): string | null { - // Remove the `aria-selected` when the chip is deselected in single-selection mode, because - // it adds noise to NVDA users where "not selected" will be read out for each chip. - return this.selectable && (this._chipListMultiple || this.selected) - ? this.selected.toString() - : null; + return this.selectable ? this.selected.toString() : null; } /** The unstyled chip selector for this component. */