-
Notifications
You must be signed in to change notification settings - Fork 76
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
refactor(modal): Update modal to use focus-trap module. #5676
Conversation
@macandcheese @geospatialem @jcfranco could you play around with this and let me know if its working correctly? |
Seems to work well! The "tab fencing" demo doesn't seem to work as described, but that may just be out of date sample content. Is it still possible to specify an element to focus first? |
Yes, that's possible with the module. Do we need to support that for modal? I didn't see anything like that. https://github.com/focus-trap/focus-trap#createoptions |
Just going off the existing content in the "tab fencing" example modal. That may just be out of date demo - we already have |
From what I understand, it's ideal to focus on the first focusable element when a component's In most cases, this will be the close button but if that is disabled it would go to the next focusable element which could be some modal content or if no focusable modal content then any footer focusable content. If we're following the rules, we shouldn't prioritize modal "content" over whatever the first focusable element is. So that demo wording should be updated. Ideally, we remove any options on setFocus. A user shouldn't be allowed or have to worry about focusing a specific element within the component. The component should handle that by focusing the first focusable element. In some components this will be a ranging focus element like the last selected radio button. |
@driskull We should also confirm if this impacts the a11y/design of things. IMO, for closable dialogs with interactive content, as a keyboard user I would expect to be able to interact with the content without an extra keypress to move focus. Note that I'm not vouching for FWIW, @benelan was looking into this topic for #5147.
Which rules are you referring to here? |
I agree with @jcfranco here regarding interactive content. I like to think of this in terms of primary action. When the dialog appears, what's my primary action? If there is interactive content, my primary action would be to interact with that content before I close the dialog. |
W3C guidelines for modal, but they are all pretty similar regarding focus. https://www.w3.org/WAI/ARIA/apg/example-index/dialog-modal/dialog
I agree its not ideal in all cases, but in those cases the user is slotting the content and the footer buttons so they can always focus on one of those once the modal is opened. I don't think we need
For these cases, we wouldn't be able to use any setFocus options to determine a primary action anyway. The author of the modal would have to focus on the primary action once the modal is opened. Which they can do because they are slotting the primary actions and those actions are in light DOM. |
Just to be clear, the only thing changing is we focus the |
If we want to provide an option in the future for which element to focus by default, we could do that with https://github.com/focus-trap/focus-trap#what-it-does
|
It seems like |
|
Ah, thanks for clarifying. I thought focus-trap was being suggested as an alternative. |
Nope! but ideally we should be consistent with how |
This looks great, @driskull! 🌟 Concur with your thoughts on the If folks think the ordering seems odd with the close button being the first focusable element we could consider moving the close button to the footer by default. It would be a new pattern for the component so we'd need some design buy in for it, but perhaps an option if folks would rather see focusable elements from the content in focus first. |
I'm not design, so take this with a grain of salt, but I don't think we should do this. If we do, we would probably need to change the "X" to "Close". I don't think I've ever seen a close "X" button in the footer, they are also in the top right. Imo changing that would cause more confusion/annoyance for users than whatever the first focusable element is. |
Many Modals won't have footers either, so the close button as currently situated makes the most sense IMO. I think the focus on the close button should be expected as we've done that for awhile. |
Correct. We've gotten feedback from a11y team that focusing close button on panel first is correct. This should align with that. |
Fair enough. As long as this is design/a11y-approved and we are consistent. Just curious, but is there an a11y example out in the wild that has a close button similar to where we place ours?
I like this. We can revisit supporting this later based on user feedback. |
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.
Awesome stuff!
return focusElement( | ||
focusId === "close-button" ? closeButton : getFocusableElements(this.el)[0] || closeButton | ||
); | ||
if (closeButtonEl && focusId === "close-button") { |
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.
Since close-button
is the only supported ID, I think you could just check for closeButtonEl
being present or not. Passing any other ID would technically be invalid, right?
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.
Correct. I think its nicer to check and fallback incase the user entered an invalid ID>
src/tests/commonTests.ts
Outdated
/** | ||
* Used to delay setFocus call in ms. | ||
*/ | ||
delay?: number; |
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.
If this is for the open/close transition, I'd suggest using the skipAnimation
helper instead of introducing a delay argument. If it's something specific to focus-trap
behavior, can you add more info about this to the documentation?
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.
@jcfranco the problem is the delayInitialFocus
is set to true.
I tried delayInitialFocus: !Build.isTesting,
but the problem is that its not returning true.
{"testing":false,"browser":true,"dev":false,"server":false}
Location: http://localhost:3333/build/p-371d7086.entry.js:15:2306
# Conflicts: # package-lock.json
* master: (24 commits) 1.0.0-next.632 feat(pick-list, value-list): Add calciteListFilter event, filteredItems prop, filterText prop and filteredData prop. (#5681) fix(block, date-picker, list-item-group, panel, pick-list-group, popover, tip, tip-manager)!: Set default internal heading to a div. (#5728) refactor(modal): Update modal to use focus-trap module. (#5676) 1.0.0-next.631 fix(input-date-picker): restores mouse clicks on date-picker popup (#5760) build(deps): bump loader-utils from 1.4.1 to 1.4.2 (#5764) ci(product-label): fix version syntax and use os agnostic newline char (#5762) 1.0.0-next.630 ci(pr-bot): don't label dependabot PRs (#5759) build(deps): bump chromatic from 6.7.1 to 6.11.4 (#5756) fix(combobox): Wrap and break text on long items (#5672) build(deps): bump @storybook/addon-interactions from 6.5.9 to 6.5.13 (#5753) build(deps): bump type-fest from 3.1.0 to 3.2.0 (#5752) build(deps): bump @storybook/addon-a11y from 6.5.12 to 6.5.13 (#5754) build(deps): bump postcss from 8.4.18 to 8.4.19 (#5755) ci: add chromatic (#5733) build(docs): generate docs-json for afd usage (#5748) 1.0.0-next.629 fix(inline-editable): Add text-ellipsis when not editing (#5679) ...
Related Issue: #1169 #5270
Summary
refactor(modal): Update modal to use focus-trap module.
@a11y/focus-trap
module with more popular and supportedfocus-trap
module.Precursor to #2133