-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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(focus-trap): apply aria-hidden to focus trap tab anchors #14644
Conversation
These anchors at the book ends of a FocusTrap'ed element have focus listeners that redirect focus back to the element. However, some screen readers may access these focus traps without moving programmatic focus, leaving the SR user wondering why an empty control lives on the page. Android TalkBack currently treats this as a stop with no announcement (because it has no content). Adding the aria-hidden should prevent these from being accessed in SR contexts while preserving the core functionality of redirecting focus when it's moved linearly (e.g., with tab).
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.
LGTM. Leaving to @jelbourn for final approval since I can see this having some side effects.
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.
LGTM, thanks!
AFAICT there shouldn't be any adverse effects from this
…#14644) These anchors at the book ends of a FocusTrap'ed element have focus listeners that redirect focus back to the element. However, some screen readers may access these focus traps without moving programmatic focus, leaving the SR user wondering why an empty control lives on the page. Android TalkBack currently treats this as a stop with no announcement (because it has no content). Adding the aria-hidden should prevent these from being accessed in SR contexts while preserving the core functionality of redirecting focus when it's moved linearly (e.g., with tab).
…#14644) These anchors at the book ends of a FocusTrap'ed element have focus listeners that redirect focus back to the element. However, some screen readers may access these focus traps without moving programmatic focus, leaving the SR user wondering why an empty control lives on the page. Android TalkBack currently treats this as a stop with no announcement (because it has no content). Adding the aria-hidden should prevent these from being accessed in SR contexts while preserving the core functionality of redirecting focus when it's moved linearly (e.g., with tab).
These anchors at the book ends of a FocusTrap'ed element have focus listeners that redirect focus back to the element. However, some screen readers may access these focus traps without moving programmatic focus, leaving the SR user wondering why an empty control lives on the page. Android TalkBack currently treats this as a stop with no announcement (because it has no content). Adding the aria-hidden should prevent these from being accessed in SR contexts while preserving the core functionality of redirecting focus when it's moved linearly (e.g., with tab).
This will cause a failure with Deque University Accessibility Checker Axe. More info can be found here:. I believe that this is a bandaid and not a solution. |
Thanks for raising this Michael. I can understand why the Axe checker recommends as it does but I believe the recommendation is imprecise or make an alternate suggestion to address the modal dialog use case. The spirit of the recommendation to my reading is to avoid accidentally obscuring semantically important focusable elements. However there are two major cases, both related to modal dialogs, where
If there's an alternative that satisfies these needs to display a usable modal dialog, please point me to it. https://www.w3.org/TR/wai-aria-practices/examples/dialog-modal/dialog.html actually fails on point 2 and doesn't even correctly hide the tab stops on point 1, causing overannouncing of semantically useless elements on some SRs. Our current approach to modal dialogs satisfies both points, has been reported as accessible by our testers, and only falls short of the letter of the Axe test. |
Thanks, @stevenyxu for your feedback. I was merely stating an observation that I had come across. The only other option that I can think of -- still not standardized, although a polyfill is available -- is the ability to mark DOM elements as inert. Thereby eliminating the need for tab stops altogether. This would also handle the debate as to whether a keyboard trap on a dialog should exclude changing the focus from the viewport to the browser itself. I.e. allowing a user to navigate via a keyboard (without the use of an SR) to the URL address bar without the need to dismiss the dialog. |
Thanks Michael. We will monitor inert and how the proposal advances. The polyfill in its current state has the same defect you reported since it relies on Additionally, inert does not address the non-modal use of tabindex traps, which would require an additional new standard (comparable to |
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. |
These anchors at the book ends of a FocusTrap'ed element have focus listeners that redirect focus
back to the element. However, some screen readers may access these focus traps without moving
programmatic focus, leaving the SR user wondering why an empty control lives on the page. Android
TalkBack currently treats this as a stop with no announcement (because it has no content). Adding
the aria-hidden should prevent these from being accessed in SR contexts while preserving the core
functionality of redirecting focus when it's moved linearly (e.g., with tab).
cdk FocusTrap adds focus trap divs with tabindex=0 at the beginning and end of the trapped container to prevent focus from leaving when pressing tab or linearly navigating. When these elements are focused, a focus handler redirects the browser focus as to effectively cycle focus within an element. This works fine for e.g., OS X VoiceOver, which generally moves focus when navigating the page. However some screenreaders may routinely browse elements without moving focus. A notable example is TalkBack, which is one of Angular Material's supported environments https://github.com/angular/material2#browser-and-screen-reader-support. This is also true in some popular configurations of JAWS/NVDA.
Settings these to have aria-hidden=true will typically cause for SRs to ignore these when linearly navigating the page, if they're not already ignored.
I've tested a primitive version of this fix on TalkBack and it works well.
https://stackblitz.com/edit/angular-e9gqbr?file=app%2Fdialog-content-example.ts
https://www.youtube.com/watch?v=SN1chzTfvTs
I can imagine some rare edge cases where this could cause a regression in functionality. In cases where cdk FocusTrap is used but were relying on SRs to "see" the focus trap anchors and shift focus to them, so that the active focus handler would redirect focus, this may break things, and SRs may wrongly shift focus to a bad spot. However, doing it this way would have been extremely finicky in the first place. If you wanted SRs not to be able to escape the focus trap, you should have set aria-hidden on the rest of the page in the first place (MatDialog does this https://github.com/angular/material2/blob/d22f48c742c0bbdc971f79ea1261ec5c20d15a69/src/lib/dialog/dialog.ts#L345, and individual application code may wrap cdk Overlay to do this; it's a bit of a mystery to me why cdk Overlay or cdk FocusTrap doesn't do this itself, but that's a separate concern). Such a page would have been a pain for SRs in the first place since heading and landmark navigation, common SR navigation techniques, could easily have shifted focus to the underlying page anyway. These users should be encouraged to apply aria-hidden appropriately. That said, we have tested this on the following SRs on the latest versions and things appear to be no worse:
Android TalkBack - my fix should address the hidden SR stop
NVDA/JAWS with virtual cursor - similar fix, but virtual cursor configuration varies greatly among users; generally, the hidden tab stops aren't problematic
OS X VO - always ignored the empty tabindex=0 anchors anyway
Internal bug reference b/122041252.