-
Notifications
You must be signed in to change notification settings - Fork 377
feat(PF4-Modal): Adds keyboard and screen reader focus trapping #1011
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
feat(PF4-Modal): Adds keyboard and screen reader focus trapping #1011
Conversation
Pull Request Test Coverage Report for Build 3518
💛 - Coveralls |
3dab5e5 to
9551ff0
Compare
|
PatternFly-React preview: https://1011-pr-patternfly-react-patternfly.surge.sh |
|
Having trouble writing tests that check that the Using // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`the React root is hidden from screen readers when the modal is open 1`] = `
<body
class="pf-c-backdrop__open"
>
<div />
<div />
<div />
<div />
<div />
<div />
</body>
`;
Notice that the Trying to see if const view = mount(<Modal {...props} isOpen />);
const spy = jest.spyOn(document.body.classList, 'add');
view.update();
expect(spy).toHaveBeenCalled();which results in failure. I tried clearing the jest cache, and sadly that didn't help. I was hoping to do the something like test('the React root is hidden from screen readers when the modal is open', () => {
document.body.appendChild(props.reactRoot);
const view = mount(<Modal {...props} isOpen />);
const spy = jest.spyOn(view.prop('reactRoot'), 'setAttribute');
view.update();
expect(spy).toHaveBeenCalledWith(stuff);
});Any ideas/suggestions here? |
|
Thanks for working on this! Everything looks good wrt screen readers. I tested in JAWS, NVDA, and VO, and all trap focus, and contents outside the modal are not accessible while the modal is visible. |
jgiardino
left a comment
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.
Works as expected!
BREAKING CHANGE: The reactRoot prop is required Fixes patternfly#561
9551ff0 to
304a00d
Compare
304a00d to
764d051
Compare
| isLarge: PropTypes.bool | ||
| isLarge: PropTypes.bool, | ||
| /** React application root element */ | ||
| reactRoot: PropTypes.instanceOf(safeHTMLElement).isRequired |
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.
could we default to document.body and make it optional?
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.
I agree this seems pretty invasive for consumers. I haven't seen this before in others. It looks like the reasoning is for setting aria-hidden? It looks like that has been deprecated/replaced by aria-modal:
https://www.w3.org/TR/wai-aria-practices/#dialog_roles_states_props
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.
Maybe checking out atlaskits? It seems their focus trap works well, but I can't speak to screen readers: https://atlaskit.atlassian.com/packages/core/modal-dialog
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.
I had tested several implementations before to see what worked across the different screen reader / browser combinations we test in. The attributes role="dialog" and aria-modal don't seem to be supported as described by wai-aria. When I test their solution using JAWS / Chrome, focus is not trapped. It also is not trapped using focus-trap-react.
Solutions that did work were:
- https://github.com/edenspiekermann/a11y-dialog
- https://github.com/gdkraus/accessible-modal-dialog
I did not test atlaskit, but will do that and let you know what the results were.
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.
Ah, bummer maybe aria-modal is not widely supported yet.
Here is another implementation to check: https://ui.reach.tech/dialog
It does not require a root, but sets aria-hidden on root elements.
Code here: https://github.com/reach/reach-ui/blob/master/packages/dialog/src/index.js#L7
Looks like it is just using document.querySelectorAll("body > *") and hides everything but the dialog root.
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.
I captured part of this discussion in a separate issue: #1037
tlabaj
left a comment
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
BREAKING CHANGE: The reactRoot prop is required
Fixes #561
What: Adds keyboard and screen reader focus trapping
Notes/Resources:
HTMLElementas a prop.aria-hidden=trueis applied to the react root element, hiding it from screen readers.aria-hiddenattribute is removed from the react root element