Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

fix(toast): improve a11y support for $mdToast.simple(). improve docs #11424

Merged
merged 1 commit into from
Sep 18, 2018

Conversation

Splaktar
Copy link
Member

PR Checklist

Please check that your PR fulfills the following requirements:

  • The commit message follows our guidelines
  • Tests for the changes have been added or this is not a bug fix / enhancement
  • Docs have been added, updated, or were not required

PR Type

What kind of change does this PR introduce?

[x] Bugfix
[ ] Enhancement
[ ] Documentation content changes
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Infrastructure changes
[ ] Other... Please describe:

What is the current behavior?

Actions within toasts are not announced at all for screen readers.
It's almost impossible to activate an action in a toast from a screen reader.
There are no instructions for screen reader users on how to dismiss a toast.

Issue Number:
Fixes #349

What is the new behavior?

move the role="alert" up a level

  • makes action button visible to screen readers
    add support for defining an actionKey to assign a hot key to an action
  • this enables Control-actionKey to activate the action
    add support for defining a dismissHint for screen readers
    add support for defining an actionHint for screen readers
    align custom toast demo with Material Design guidelines
    enhance custom toast demo to demonstrate an accessible custom toast

Does this PR introduce a breaking change?

[ ] Yes
[x] No

Other information

@Splaktar Splaktar added type: bug a11y This issue is related to accessibility g3: reported The issue was reported by an internal or external product team. P1: urgent Urgent issues that should be addressed in the next minor or patch release. labels Aug 24, 2018
@Splaktar Splaktar added this to the 1.1.11 milestone Aug 24, 2018
@googlebot googlebot added the cla: yes PR author has signed Google's CLA: https://opensource.google.com/docs/cla/ label Aug 24, 2018
@Splaktar Splaktar requested a review from jelbourn August 24, 2018 02:12
@Splaktar Splaktar added the pr: merge ready This PR is ready for a caretaker to review label Aug 24, 2018
* <td>`.actionKey(string)`</td>
* <td>
* Adds a hot key for the action button. <br/>
* If the `actionKey` and Control are pressed, the toast's action will be triggered.<br>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always having this be based on control seems a little too specific. The user might want to do ctrl + shift or even just a single key. Gmail, for example, uses just z for undo. For MatSnackbar, we just document that the user should add their own keyboard shortcut.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. However this only applies to the "simple" toasts.

If developers need more flexible options, then the custom toast demo was updated to demonstrate how to setup custom keyboard shortcuts.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also happy to extend this API to accept values for the metaKey, ctrlKey, shiftKey, and altKey should the request arise.

Do you think that we should just go ahead and support those now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel super strongly either way.

options: /* @ngInject */ function($mdToast, $mdTheming) {
return {
template:
'<md-toast md-theme="{{ toast.theme }}" ng-class="{\'md-capsule\': toast.capsule}">' +
' <div class="md-toast-content">' +
' <span class="md-toast-text" role="alert" aria-relevant="all" aria-atomic="true">' +
' <div class="md-toast-content" role="alert" aria-relevant="all">' +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using role="alert" isn't really the best pattern for snackbars. alert is a more specific type of dialog, which are inherently interuptive, while snackbars are meant to be non-interuptive.

The recommend approach is to use an aria-live region (polite) for the text of the notification (which is what the MatSnackbar does)

Copy link
Member Author

@Splaktar Splaktar Aug 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into using $mdLiveAnnouncer which does enable the use of role="status" live regions with aria-live="polite" but the current implementation of it does not work well with interim elements like toasts.

I'm not 100% sure, but I believe for the current implementation to work properly, the $mdLiveAnnouncer needs to be injected in a component that is longer lived. This might work fine if other components are using $mdLiveAnnouncer and you add a toast, but it doesn't seem to work if you only add the toast w/o any other components to trigger instantiation earlier.

The description of the alert role does seem to align well with the behavior of snackbars and toasts.

The alertdialog role does not, as it better fits a modal dialog.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you're right, I mixed up alert and alertdialog. In that case you should be able to swap role="alert" with aria-live="polite" and get the same treatment. Not going through the live announcer isn't ideal, but AFAIK it should work most of the time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I swap to role="status" then it should default to aria-live="polite". However, it seems like a snackbar with an interactive button / hotkey would better fit the alert role versus the status role.

The other downside here is that role="status" is broken in Chromevox until Chrome M70.

It looks like role="alert" aria-live="polite" together may be the best fit. I'll do some more testing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, adding both isn't a good idea as it causes double reading of the messages.

However, polite in most cases (with our current defaults and demos) causes the toast to be read after the toast times out and disappears. This means that by the time the user heard the instructions for interacting, the toast would be gone.

To mitigate this, I've added instructions to the hideDelay docs to recommend setting it to 0 when the toast includes an action. I would like to do this automatically for simple toasts, but I will avoid it for now since it might cause some g3 tests to fail. I've also updated the demos to use hideDelay(0) when they have an action.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't believe role="status" is widely supported.

The Material Design team also says that snackbars shouldn't auto-dismiss when they have an action, so that would indeed be the right behavior.

move the role="alert" up a level
 - makes action button visible to screen readers
add support for defining an actionKey to assign a hot key to an action
- this enables Control-actionKey to activate the action
add support for defining a dismissHint for screen readers
add support for defining an actionHint for screen readers
align custom toast demo with Material Design guidelines
enhance custom toast demo to demonstrate an accessible custom toast

Fixes #349
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Splaktar Splaktar added the pr: lgtm This PR has been approved by the reviewer label Aug 27, 2018
' <span class="md-visually-hidden">{{ toast.dismissHint }}</span>' +
' <span class="md-visually-hidden" ng-if="toast.action">' +
' {{ toast.actionHint }}' +
' </span>' +
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new dismissHint and actionHint span elements are returned by tests that do .find('span').text() like expect(parent.find('span').text().trim()).toBe('Do something');. So the tests will now get the all of the contents (even the contents of the two new md-visually-hidden spans). This broke two AngularJS Material tests, but it appears to be breaking some tests within Google as well.

Can anyone think of any way to work around this that doesn't mean changing all of the tests?

This is in an Aria Live Region, so I don't think that something like aria-describedby would be a valid workaround.

I wonder if wrapping the new elements in a div or changing them to divs would work. It seems like it may break screen readers but I will test it.

  • Test wrapping dismissHint and actionHint span elements in divs
  • Test changing dismissHint and actionHint span elements to divs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jeremy indicated that it should actually be easy to fix the 2 tests within Google that are broken by this.

@Splaktar Splaktar added pr: presubmit-failures in progress Mainly for in progress PRs, but may be used for issues that require multiple PRs and removed pr: merge ready This PR is ready for a caretaker to review labels Aug 30, 2018
@Splaktar Splaktar added pr: merge ready This PR is ready for a caretaker to review and removed in progress Mainly for in progress PRs, but may be used for issues that require multiple PRs pr: presubmit-failures labels Sep 7, 2018
@mmalerba mmalerba merged commit fedb9a3 into master Sep 18, 2018
@Splaktar Splaktar deleted the fixToastA11y branch September 18, 2018 22:14
nobitagit pushed a commit to nobitagit/material that referenced this pull request Sep 24, 2018
…ngular#11424)

move the role="alert" up a level
 - makes action button visible to screen readers
add support for defining an actionKey to assign a hot key to an action
- this enables Control-actionKey to activate the action
add support for defining a dismissHint for screen readers
add support for defining an actionHint for screen readers
align custom toast demo with Material Design guidelines
enhance custom toast demo to demonstrate an accessible custom toast

Fixes angular#349
marosoft pushed a commit to marosoft/material that referenced this pull request Nov 11, 2018
…ngular#11424)

move the role="alert" up a level
 - makes action button visible to screen readers
add support for defining an actionKey to assign a hot key to an action
- this enables Control-actionKey to activate the action
add support for defining a dismissHint for screen readers
add support for defining an actionHint for screen readers
align custom toast demo with Material Design guidelines
enhance custom toast demo to demonstrate an accessible custom toast

Fixes angular#349
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a11y This issue is related to accessibility cla: yes PR author has signed Google's CLA: https://opensource.google.com/docs/cla/ g3: reported The issue was reported by an internal or external product team. P1: urgent Urgent issues that should be addressed in the next minor or patch release. pr: lgtm This PR has been approved by the reviewer pr: merge ready This PR is ready for a caretaker to review type: bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

toast: needs to support non-visual & keyboard users
6 participants