-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
fix(multiple): fix VoiceOver confused by Select/Autocomplete's ARIA semantics #26861
Conversation
Deployed dev-app for b697571 to: https://ng-dev-previews-comp--pr-angular-components-26861-kaqryhf5.web.app Note: As new commits are pushed to this pull request, this link is updated after the preview is rebuilt. |
7033c3c
to
86cc57e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(same comments for select as autocomplete)
const modals = this._document.querySelectorAll( | ||
'body > .cdk-overlay-container [aria-modal="true"]', | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need all modals here, should we? I think we should theoretically only need the closest modal ancestor of the autocomplete trigger
const modal = this.element.nativeElement.closest('[aria-modal="true"]');
|
||
/** Clears the references to the listbox overlay element from any modals it was added to. */ | ||
private _clearFromModals() { | ||
this._trackedModals.forEach(modal => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer for
to forEach
https://github.com/angular/angular/blob/main/docs/CODING_STANDARDS.md#iteration
(but if we only end up tracking one, you wouldn't need this anyway)
It also occured to me that the code to add/remove an ID from an existing attribute string is very similar to what |
196a245
to
d1ea562
Compare
Still working on this PR. I noticed an issue that only happens when using VoiceOver with Firefox. It works fine when using Firefox without voiceover and it works fine on Chrome. Pressing up/down keys does not move the active option. When the panel opens, Work-around is to use VO + Up/Down, which work normally. |
Remove the tabindex attribute from MatOption. MatOption will no longer set a tabindex. Tabindex is not needed since focus is managed on the parent by setting `aria-activedescendant`. Tabindex="-1" seems to be causing a problem in angular#26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup.
Remove the tabindex attribute from MatOption. MatOption will no longer set a tabindex. Tabindex is not needed since focus is managed on the parent by setting `aria-activedescendant`. Tabindex="-1" seems to be causing a problem in angular#26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup.
Remove the tabindex attribute from MatOption. MatOption will no longer set a tabindex. Tabindex is not needed since focus is managed on the parent by setting `aria-activedescendant`. Tabindex="-1" seems to be causing a problem in angular#26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup.
Remove the tabindex attribute added to MatOption components. MatOption does not need tabindex because the parent component manages focus by setting `aria-activedescendant` attribute. Previously, MatOption set tabindex but was also a referenced by aria-activedescendant. This was not the correct ARIA semantics. Align closer to ARIA spec by using only aria-activedescendant rather than both. Tabindex="-1" seems to be causing a problem in angular#26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup. Unblocks angular#26861.
Remove the tabindex attribute added to MatOption components. MatOption does not need tabindex because the parent component manages focus by setting `aria-activedescendant` attribute. Previously, MatOption set tabindex but was also a referenced by aria-activedescendant. This was not the correct ARIA semantics. Align closer to ARIA spec by using only aria-activedescendant rather than both. Tabindex="-1" seems to be causing a problem in angular#26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup. Unblocks angular#26861.
Remove the tabindex attribute added to MatOption components. MatOption does not need tabindex because the parent component manages focus by setting `aria-activedescendant` attribute. Previously, MatOption set tabindex but was also a referenced by aria-activedescendant. This was not the correct ARIA semantics. Align closer to ARIA spec by using only aria-activedescendant rather than both. Tabindex="-1" seems to be causing a problem in angular#26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup. Unblocks angular#26861.
Remove the tabindex attribute added to MatOption components. MatOption does not need tabindex because the parent component manages focus by setting `aria-activedescendant` attribute. Previously, MatOption set tabindex but was also a referenced by aria-activedescendant. This was not the correct ARIA semantics. Align closer to ARIA spec by using only aria-activedescendant rather than both. Tabindex="-1" seems to be causing a problem in angular#26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup. Unblocks angular#26861.
Remove the tabindex attribute added to MatOption components. MatOption does not need tabindex because the parent component manages focus by setting `aria-activedescendant` attribute. Previously, MatOption set tabindex but was also a referenced by aria-activedescendant. This was not the correct ARIA semantics. Align closer to ARIA spec by using only aria-activedescendant rather than both. Tabindex="-1" seems to be causing a problem in angular#26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup. Unblocks angular#26861.
Remove the tabindex attribute added to MatOption components. MatOption does not need tabindex because the parent component manages focus by setting `aria-activedescendant` attribute. Previously, MatOption set tabindex but was also a referenced by aria-activedescendant. This was not the correct ARIA semantics. Align closer to ARIA spec by using only aria-activedescendant rather than both. Tabindex="-1" seems to be causing a problem in #26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup. Unblocks #26861.
Remove the tabindex attribute added to MatOption components. MatOption does not need tabindex because the parent component manages focus by setting `aria-activedescendant` attribute. Previously, MatOption set tabindex but was also a referenced by aria-activedescendant. This was not the correct ARIA semantics. Align closer to ARIA spec by using only aria-activedescendant rather than both. Tabindex="-1" seems to be causing a problem in #26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup. Unblocks #26861. (cherry picked from commit 97410fa)
Remove the tabindex attribute added to MatOption components. MatOption does not need tabindex because the parent component manages focus by setting `aria-activedescendant` attribute. Previously, MatOption set tabindex but was also a referenced by aria-activedescendant. This was not the correct ARIA semantics. Align closer to ARIA spec by using only aria-activedescendant rather than both. Tabindex="-1" seems to be causing a problem in #26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup. Unblocks #26861. (cherry picked from commit 97410fa)
4c4146f
to
c3a0204
Compare
c3a0204
to
30691a9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is currently tagged with major
, but should it actually be minor
?
Looks good, just a few last nits
const modal = this._element.nativeElement.closest( | ||
'body > .cdk-overlay-container [aria-modal="true"]', | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason this selector couldn't just be [aria-modal="true"]
by itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm aligning this with how SnackBarContainer
and LiveAnnouncer do it. They only intend to implement for Overlay component, but there's a TODO to consolidate the duplicated code and consider making it work more broadly.
http://github.com/angular/components/issues/26853
Thanks for reviewing. This PR adds aria-reference.ts to public api. this PR doesn't actually remove or deprecate anything or make breaking changes. Set the target to minor. |
…emantics For Select and Autcomplete components, fix issues where VoiceOver was confused by the ARIA semantics of the combobox. Fix multiple behaviors: - Fix VoiceOver focus ring stuck on the combobox while navigating options. - Fix VoiceOver would sometimes reading option as a TextNode and not communicating the selected state and position in set. - Fix VoiceOver "flickering" behavior where VoiceOver would display one announcement then quickly change to another annoucement. Fix the same issues for both Select and Autocomplete component. Implement fix by correcting the combobox element and also invidual options. First, move the aria-owns reference to the overlay from the child of the combobox to the parent modal of the comobobx. Having an aria-owns reference inside the combobox element seemed to confuse VoiceOver. Second, apply `aria-hidden="true"` to the ripple element and pseudo checkboxes on mat-option. These DOM nodes are only used for visual purposes, so it is most appropriate to remove them from the accessibility tree. This seemed to make VoiceOver's behavior more consistent. Fix angular#23202 Fix angular#19798
30691a9
to
b697571
Compare
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
For Select and Autcomplete components, fix issues where VoiceOver was confused
by the ARIA semantics of the combobox. Fix multiple behaviors:
options.
communicating the selected state and position in set.
announcement then quickly change to another annoucement.
Fix the same issues for both Select and Autocomplete component.
Implement fix by correcting the combobox element and also invidual
options.
First, move the aria-owns reference to the overlay from the child of the
combobox to the parent modal of the comobobx. Having an aria-owns
reference inside the combobox element seemed to confuse VoiceOver.
Second, apply
aria-hidden="true"
to the ripple element and pseudocheckboxes on mat-option. These DOM nodes are only used for visual
purposes, so it is most appropriate to remove them from the
accessibility tree. This seemed to make VoiceOver's behavior more
consistent.
Fix #23202, #19798