Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snackbars not read by screen reader #29080

Closed
2 tasks done
TheWilks opened this issue Oct 15, 2021 · 12 comments 路 Fixed by #30774 路 May be fixed by #29975
Closed
2 tasks done

Snackbars not read by screen reader #29080

TheWilks opened this issue Oct 15, 2021 · 12 comments 路 Fixed by #30774 路 May be fixed by #29975
Labels
accessibility a11y component: snackbar This is the name of the generic UI component, not the React module! docs Improvements or additions to the documentation

Comments

@TheWilks
Copy link

  • The issue is present in the latest release.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 馃槸

Snackbars are not being read by a screen reader in various scenarios but the majority of the issues are with Firefox...

  1. NVDA screen reader + Firefox: Screen reader is not reading the snackbar when triggering it with a button
  2. NVDA screen reader + Firefox: Screen reader is not reading the snackbar when triggering it with a menu
  3. NVDA screen reader + Firefox: Screen reader is not reading the snackbar when triggering it with a button within a dialog
  4. NVDA screen reader + Chrome: Screen reader is not reading the snackbar when triggering it with a button within a dialog

Expected Behavior 馃

Snackbar should always be read by the screen reader no matter the scenario.

Steps to Reproduce 馃暪

https://codesandbox.io/s/snackbar-accessibility-s58hj?file=/App.js

Context 馃敠

We are trying to release a product that needs to be accessible and will not be able to release the product if this issue is not resolved. We are in the process of figuring out a work around. Our current solution is to not use the snackbars but to use alerts instead. We still need to do more testing but the alerts seem to function better. We have also done some testing with the Web version of the Material IO snackbar and it seems to function better. We have also tested many Google products that also function correctly.

@TheWilks TheWilks added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Oct 15, 2021
@TheWilks
Copy link
Author

TheWilks commented Oct 22, 2021

Made some progress on getting things to read better with a screen reader in Firefox. The snackbar triggered from a button now reads in Chrome, Firefox and Edge using NVDA and JAWS.

The only remaining issue is when the user triggers the snackbar by clicking a button within a dialog.

https://codesandbox.io/s/dialog-snackbar-testing-sje9p?file=/demo.js

@mbrookes
Copy link
Member

mbrookes commented Oct 22, 2021

@TheWilks Thanks for sharing your progress. It would be good to know what you did to fix these issues, and whether you believe there's anything that needs to be fixed in the component, or whether it's a documentation issue.

@TheWilks
Copy link
Author

TheWilks commented Oct 22, 2021

@TheWilks Thanks for sharing your progress. IT would be good to know what you did to fix these issues, and whether you believe there's anything that needs to be fixed in the component, or whether it's a documentation issue.

So the issue (from what I can tell) is that there are multiple role="alert" at different levels. So in my use case I use "Snackbars" combined with "Alerts" and both of these components have role="alert" so I set both to role="none" and wrapped the alert message in a span with role="alert". This seems to have fixed the issues across Chrome, Firefox and Edge when using NVDA and JAWS.

Also it made sense to only target the message with role="alert" because the user is not focused on the snackbar so a keyboard user cannot easily access any snackbar buttons when they are announced (this is what Material IO seems to do as well https://material-components.github.io/material-components-web-catalog/#/component/snackbar).

All that said I have yet to find a solution for triggering a snackbar from a button within a dialog. This is an issue across all the browsers and screen readers I have mentioned above.

@mbrookes mbrookes added docs Improvements or additions to the documentation component: snackbar This is the name of the generic UI component, not the React module! and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Oct 24, 2021
@TheWilks
Copy link
Author

TheWilks commented Oct 25, 2021

Findings

I have done a lot of testing and have found a solution that works in every scenario except 1. The issue seems to be mainly with the dialog component. In my use case I am triggering the snackbar when the user clicks the primary button within the dialog and also closing the dialog on click as well. If I place the snackbar inside the dialog it reads fine but because I also close the dialog at this point I must place the snackbar in 2 places... 1 inside the dialog for the screen reader and 2 outside the dialog for the visual user. As mentioned above there is still 1 scenario that is failing (Trigger snackbar with button in a dialog Firefox NVDA using mouse). See my solution and testing results below.

Current solution

https://codesandbox.io/s/snackbar-final-15gum?file=/demo.js

Testing results

Trigger snackbar with button...

  • (PASS) Chrome NVDA using keyboard
  • (PASS) Chrome NVDA using mouse
  • (PASS) Firefox NVDA using keyboard
  • (PASS) Firefox NVDA using mouse
  • (PASS) Edge NVDA using keyboard
  • (PASS) Edge NVDA using mouse
  • (PASS) Chrome JAWS using keyboard
  • (PASS) Chrome JAWS using mouse
  • (PASS) Firefox JAWS using keyboard
  • (PASS) Firefox JAWS using mouse
  • (PASS) Edge JAWS using keyboard
  • (PASS) Edge JAWS using mouse

Trigger snackbar with menu...

  • (PASS) Chrome NVDA using keyboard
  • (PASS) Chrome NVDA using mouse
  • (PASS) Firefox NVDA using keyboard
  • (PASS) Firefox NVDA using mouse
  • (PASS) Edge NVDA using keyboard
  • (PASS) Edge NVDA using mouse
  • (PASS) Chrome JAWS using keyboard
  • (PASS) Chrome JAWS using mouse
  • (PASS) Firefox JAWS using keyboard
  • (PASS) Firefox JAWS using mouse
  • (PASS) Edge JAWS using keyboard
  • (PASS) Edge JAWS using mouse

Trigger snackbar with button in a dialog...

  • (PASS) Chrome NVDA using keyboard
  • (PASS) Chrome NVDA using mouse
  • (PASS) Firefox NVDA using keyboard
  • (FAIL) Firefox NVDA using mouse
  • (PASS) Edge NVDA using keyboard
  • (PASS) Edge NVDA using mouse
  • (PASS) Chrome JAWS using keyboard
  • (PASS) Chrome JAWS using mouse
  • (PASS) Firefox JAWS using keyboard
  • (PASS) Firefox JAWS using mouse
  • (PASS) Edge JAWS using keyboard
  • (PASS) Edge JAWS using mouse

@mbrookes
Copy link
Member

mbrookes commented Oct 26, 2021

@TheWilks Thanks so much for deep diving into this and sharing your results! Forgive me for not trying to answer my own question, but is there anything we need to improve in MUI, either in the components themselves, or the accessibility section of the respective docs? If so, a PR would be awesome!

@TheWilks
Copy link
Author

TheWilks commented Nov 9, 2021

So my main take always from testing the snackbars with NVDA/JAWS with Chrome/Firefox/Edge are...

  • Issue 1: In snackbar component all parent elements should not have "role=alert" and only the message should be have "role=alert". this fixes most of the issues I encountered.

Simple snackbar...

roleAlertIssue

Alert snackbar...

roleAlertIssue2

  • Issue 2: Launching a snackbar from a button within a dialog does not work unless you include the snackbar in the dialog itself but then you must duplicate the snackbar outside the dialog for a visual user. More investigation needs to be done here I should not need to duplicate the snackbar within the dialog. It is possible that the issue stems from the refocusing on the button that first launched the dialog once the dialog is closed. I do not have a solution for this issue.

I have not had a chance to do a PR but if my schedule frees up I will look into it. The first issue seems like a simple fix but I recommend testing it. The second issue seems much more complex and would require a lot of testing but I am available to help with this.

@eps1lon
Copy link
Member

eps1lon commented Nov 30, 2021

@TheWilks Why do you need <Snackbar role="none" />? The role on Snackbar has no effect as far as I can tell since you have explicit children.

It seems like the best thing would be to move the role="alert" down to just the message container as you've done.

Then we can think about fixing interactions with modal-like components. I suspect there's a timing issue.

@eps1lon
Copy link
Member

eps1lon commented Nov 30, 2021

Note that moving role="alert" around will not fix all cases since NVDA has an issue if the parent of role="alert" has a click handler. This is the main reason why our current implementation fails i.e. the following JSX will not cause announcement of the alert message in NVDA 2021.2 and Firefox 94:

  return (
    open && (
      <div onClick={() => {}}>
        <div role="alert">{message}</div>
      </div>
    )
  );

-- https://codesandbox.io/s/snackbar-alert-nvda-issues-fdcrd?file=/src/App.js

The click handler in our case is attached by React itself (it's literally a no-op) so we won't be able to fix all cases. Note that I don't think this is a React issue. NVDA seems to have flawed heuristics that look at the existence of click handlers when that doesn't tell you if an element is actually clickable.

React only attaches that click handler for mobile Safari: https://github.dev/facebook/react/blob/0cc724c777930438d92727803826a44ec97bcc55/packages/react-dom/src/client/ReactDOMComponent.js#L258-L269.

The reason we need to track click events is that our ClickAwayListener attaches an onClick to the wrapping div. We need it to detect click-ways in the React tree. If we remove it (and detect click-aways via element.contains), portaled content will not be detected properly (e.g. <Snackbar><Portal>Action</Portal></Snackbar> would break). This is probably ok-ish for Snackbar but breaks general composability assumptions.

So two things to do:

@TheWilks
Copy link
Author

@TheWilks Why do you need <Snackbar role="none" />? The role on Snackbar has no effect as far as I can tell since you have explicit children.

It seems like the best thing would be to move the role="alert" down to just the message container as you've done.

Then we can think about fixing interactions with modal-like components. I suspect there's a timing issue.

Agree. The role="none" was added for testing.

@TheWilks
Copy link
Author

TheWilks commented Dec 6, 2021

@eps1lon Are the proposed fixes from #29975 also meant to address the dialog issues or should I open a new issue?

@eps1lon
Copy link
Member

eps1lon commented Dec 6, 2021

@eps1lon Are the proposed fixes from #29975 also meant to address the dialog issues or should I open a new issue?

That'd be nice. It may be unrelated but even if it isn't it should be a separate issue.

@eps1lon
Copy link
Member

eps1lon commented Jan 25, 2022

Potential solution proposed in #30774

You can try the fix locally by adding role="presentation" e.g. <Snackbar role="presentation" />

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accessibility a11y component: snackbar This is the name of the generic UI component, not the React module! docs Improvements or additions to the documentation
Projects
None yet
3 participants