-
Notifications
You must be signed in to change notification settings - Fork 6.8k
fix(material/dialog): improve screen reader support when opened #23085
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
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.
Also worth noting that the commit message mentions the MDC dialog, but all the changes are to the non-MDC one.
@crisbeto I was only testing against the MDC-dialog, but they both use the same code for this. How should I write the commit message in that case? |
So after looking into this some more, here's what I've got to work with
|
0e636aa
to
abffbf3
Compare
abffbf3
to
d59d5eb
Compare
I think the check should happen in the dialog service since it is the one that determines if a dialog can open. One thing that I hadn't really considered when I posted my comment is what we would return if we decide not to open a dialog. We can't create a dialog ref without actually creating the dialog. |
Right. For the moment, I'm throwing an |
I'm not sure that throwing the error would be the right thing either, because it would be a breaking change and consumers wouldn't have a way of fixing it. |
I don't quite follow how these changes would be fixing the dialog information not being read. What mechanically is changing about how focus is set that leads to the cause in behavior change? |
Agreed, but I don't have a better approach in mind atm. We could do a different breaking change to have |
The quick swap of the focus from the trigger button to the dialog container and then to the first focusable element in the dialog is what causes the screen reader to bail out and not announce anything other than being on a focusable element. This approach does work to avoid multiple dialogs being opened while one is animating open. I've verified two paths to fixing this, while still avoiding multiple dialogs being opened while one is animating open
|
So to make sure I understand correctly: Previously, the dialog always focused itself, and then moved focus to the first tabbable elements / cdkFocusInitial element once the animation finishes? With the PR, this focus only ever goes to the configured element once the animation finishes without going to the container? How does the case of multiple dialogs opening simultaneously play into this? Is it just that they fight for focus in a way that messes up the reader? Rather than throwing an error for this case, we could try to figure out if we can decide not to care as much about that case, since multiple/nested modal dialogs are already somewhat of an anti-pattern. |
To provide some context: this bouncing around of focus was introduced, because if you have a button that opens a dialog and you press it using the keyboard, you could end up triggering multiple "clicks" if your finger lingers on the button a bit longer than expected. This is made more likely by the fact that we only move focus away from the button once the ~300ms dialog animation has finished. |
Ah, I see. What do you think about setting the activeElement to |
I haven't actually tried it, but I would assume that setting
We can always try it and see what happens. We could also try to do something where we save the trigger element when a dialog is opened. If another one is triggered while the dialog is animating, we return the previous dialog ref. |
presubmit (internal) had build failures last night 🤦 . I fixed the build failures, and will run the tests tonight 🤞 . |
@devversion this code seems to run fine on all platforms other than iOS (Sauce Labs). components/src/material-experimental/mdc-dialog/dialog.spec.ts Lines 1330 to 1339 in 087ed2c
components/src/material-experimental/mdc-dialog/dialog.spec.ts Lines 1370 to 1380 in 087ed2c
I'm not sure why it was passing before, but now it's failing with the changes in this PR, but only on iOS. |
@Splaktar Not sure from the top of my head. This seems like something that needs to be investigated within the emulator. |
The internal test results are available, 13 broken targets. |
Great! Are any of those related to iOS? |
I am able to reproduce these iOS test failures in a Simulator locally, investigating... |
e6b838d
to
235b0bc
Compare
I did a quick glance at the internal failures. They're mostly screenshot failures, and don't look iOS related. Jeremy and I are going over them in more detail later this afternoon. |
OK, I think that I've got a solution for the iOS test failures on Sauce Labs. It works locally and now I'm just waiting on this CI run to confirm. |
- notify screen reader users that they have entered a dialog - previously only the focused element would be read i.e. "Close Button Press Search plus Space to activate" - now the screen reader user gets the normal dialog behavior, which is to read the dialog title, role, content, and then tell the user about the focused element - this matches the guidance here: https://www.w3.org/TR/wai-aria-practices-1.1/examples/dialog-modal/dialog.html - Avoid opening multiple of the same dialog before animations complete by returning the previous `MatDialogRef` - update material/dialog API golden file Fixes angular#21840
235b0bc
to
5dd0503
Compare
Resolved conflict in test. |
@zarend any progress with these presubmit failures? |
yes, I have a passing presubmit, which I got to pass by patching failing tests 🎉 . I am the caretaker today and tomorrow, so I'll merge and sync this PR after we finish the sync that's in progress. |
ohh, we still need PR reviews for this. |
@@ -218,7 +215,13 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet { | |||
break; | |||
case true: | |||
case 'first-tabbable': | |||
this._focusTrap.focusInitialElementWhenReady(); | |||
this._focusTrap.focusInitialElementWhenReady().then(focusedSuccessfully => { |
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.
Im not too sure if this can have a target of patch. This is touching code from #22780, which will go into the next minor release.
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.
Also, does sidenav or bottom sheet need special handling too?
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.
@amysorto Special handling when opening to support screen readers? Probably not, unless they did the bouncing of focus that dialog did prior to this PR.
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 should double-check that they don't
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.
- Check that bottom sheet behaves properly in a screen reader when opened
- Check that sidenav behaves properly in a screen reader when opened
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.
@zarend found some similar issues with Bottom Sheet and he's investigating them now.
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 seems reasonable to me 👍
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
@@ -218,7 +215,13 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet { | |||
break; | |||
case true: | |||
case 'first-tabbable': | |||
this._focusTrap.focusInitialElementWhenReady(); | |||
this._focusTrap.focusInitialElementWhenReady().then(focusedSuccessfully => { |
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 should double-check that they don't
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. |
i.e. "Close Button Press Search plus Space to activate"
read the dialog title, role, content, and then tell the user about the
focused element
- this matches the guidance here:
https://www.w3.org/TR/wai-aria-practices-1.1/examples/dialog-modal/dialog.html
the previous
MatDialogRef
Fixes #21840