Skip to content

fix(material/chips): don't remove aria-selected from deselected options #25748

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions src/material/chips/chip-listbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand All @@ -548,23 +548,23 @@ 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();
expect(getAriaSelected()).toEqual(['true', 'true', 'true']);

primaryActions[1].click();
fixture.detectChanges();
expect(getAriaSelected()).toEqual(['true', null, 'true']);
expect(getAriaSelected()).toEqual(['true', 'false', 'true']);
}));
});

Expand Down
2 changes: 1 addition & 1 deletion src/material/chips/chip-option.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
20 changes: 14 additions & 6 deletions src/material/chips/chip-option.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down