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(material/snack-bar): flaky screen reader announcements for NVDA/JAWS #20487
Conversation
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.
My understanding is that this will only be a problem for snack bars that don't have an announcementMessage
. What if, instead of setting a role on the container, we announced the textContent
of the container with the LiveAnnouncer
, when an announcementMessage
isn't specified? The advantage would be that we won't have to add the extra timeout and we'll avoid having to move DOM nodes around.
6c2c961
to
3929ef1
Compare
I had previously considered an approach like you describe, using
Maybe a |
3929ef1
to
c47ba0d
Compare
c47ba0d
to
01372a2
Compare
src/material-experimental/mdc-snack-bar/snack-bar-container.html
Outdated
Show resolved
Hide resolved
// If an element in the snack bar content is focused before being moved | ||
// track it and restore focus after moving to the live region. | ||
let previouslyFocusedEle: HTMLElement | null = null; | ||
if (this._platform.isBrowser && |
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.
Are the isBrowser
check and the instanceof HTMLElement
strictly necessary?
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.
The instanceof HTMLElement
check is because document.activeElement
is type Element
which doesn't implement focus
. So I check to make sure the active element is of type HTMLElement
and therefore focusable.
I found without including the isBrowser
check I would get some view_engine test failures related to document
not existing. For mdc-snack-bar
with the switch back to using setTimeout
the call to _screenReaderAnnounce
is already nested in a isBrowser
check, so I've removed the redundant one. For snack-bar
I've kept the check because it isn't done elsewhere in the component.
Here's an example test failure: https://app.circleci.com/pipelines/github/angular/components/13171/workflows/d5670bcf-b85d-4721-8372-86b96b5f872f/jobs/187667/parallel-runs/0/steps/0-107
f70b92b
to
f3cdd40
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.
Overall looks good, just one last comment about the extra change detection cycle from setTimeout
f3cdd40
to
4dd51ed
Compare
b12cd20
to
0628e6d
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.
LGTM
Caretaker note: let me know if this results in a lot of failures
Fixes a bug where NVDA won't announce polite snack bars and JAWS won't announce any. This is because the live region (snack-bar-container) was added to the DOM, marked as a live region, and content was added to it in the same operation. Some screen readers require the live region to be added to the DOM, some time to pass, then content can be added. Now the snack bar content is added to an aria-hidden div then, 150ms later, moved to a div with aria-live defined. This won't cause any visual changes and keeps the snack bar content available immediatly after opening. Also, no longer using the alert or status roles. Instead just using aria-live as testing showed that NVDA will double announce with the alert role and JAWS won't announce any button text. BREAKING CHANGE: matSnackBarHarness.getRole() replaced with .getAriaLive() due to using aria-live rather than the alert and status roles.
0628e6d
to
320b2c9
Compare
…AWS (angular#20487) Fixes a bug where NVDA won't announce polite snack bars and JAWS won't announce any. This is because the live region (snack-bar-container) was added to the DOM, marked as a live region, and content was added to it in the same operation. Some screen readers require the live region to be added to the DOM, some time to pass, then content can be added. Now the snack bar content is added to an aria-hidden div then, 150ms later, moved to a div with aria-live defined. This won't cause any visual changes and keeps the snack bar content available immediatly after opening. Also, no longer using the alert or status roles. Instead just using aria-live as testing showed that NVDA will double announce with the alert role and JAWS won't announce any button text. BREAKING CHANGE: matSnackBarHarness.getRole() replaced with .getAriaLive() due to using aria-live rather than the alert and status roles.
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. |
Fixes a bug where NVDA won't announce polite snack bars and JAWS won't announce any.
This is because the live region (snack-bar-container) was added to the DOM, marked as a live
region, and content was added to it in the same operation. Some screen readers require the live
region to be added to the DOM, some time to pass, then content can be added. Now the snack bar
content is added to an aria-hidden div then, 150ms later, moved to a div with aria-live defined.
This won't cause any visual changes and keeps the snack bar content available immediatly after
opening. Also, no longer using the alert or status roles. Instead just using aria-live as testing
showed that NVDA will double announce with the alert role and JAWS won't announce any button text.
BREAKING CHANGE: matSnackBarHarness.getRole() replaced with .getAriaLive() due to using aria-live
rather than the alert and status roles.