-
Notifications
You must be signed in to change notification settings - Fork 198
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
Use ModalDialog in the notebook #6162
Conversation
384f966
to
29751e7
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #6162 +/- ##
=======================================
Coverage 99.44% 99.44%
=======================================
Files 264 264
Lines 10051 10055 +4
Branches 2386 2387 +1
=======================================
+ Hits 9995 9999 +4
Misses 56 56 ☔ View full report in Codecov by Sentry. |
11c9684
to
30e134f
Compare
'fixed z-max top-0 left-0 right-0 bottom-0 p-3 bg-black/50', | ||
{ hidden: isHidden }, | ||
)} | ||
className={classnames({ hidden: isHidden })} |
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 considered moving this to the ModalDialog
classes, but since we are not removing it from the DOM but just hiding it, that left the backdrop still visible.
30e134f
to
feb020a
Compare
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.
A few things I noticed when testing:
- With Chrome and VoiceOver, opening the notebook from "Open Notebook" in the client for the first time focuses the iframe and announces the user is in a dialog as expected
- If the user opens the notebook for a second time, focus does not move into the iframe however
- After tabbing out of the notebook iframe, focus remains trapped on the "close notebook" button, and it isn't possible to tab back into the notebook frame
- In Safari, the notebook iframe is not focused the first time it opens. I believe this is a known issue that also affects the sidebar and so I think we can discount it here.
feb020a
to
31458ee
Compare
Hhmm, I think the focus issues and the different behavior between first time and following times is related with what I mention in the "Considerations" section of the PR description. Since the modal itself is always present in the DOM and just hidden/shown, screen readers probably don't consider it a new element to announce. I'm going to try and verify this. If that's the case, I'll create another PR trying to fix that first. |
I can confirm this issue is caused by not removing the modal from the DOM when we close it. EDIT: To be more precise, it is caused by the fact that |
31458ee
to
8cdd15b
Compare
8cdd15b
to
e400d6c
Compare
After a lot of debugging, I have realized this is caused by the Modal's built-in focus trap functionality. This internally uses the The query uses a selector which is If I add I'll have to dig a bit further on this, and potentially tweak the |
const component = mount( | ||
<NotebookModal | ||
eventBus={eventBus} | ||
config={{ notebookAppUrl: notebookURL, ...config }} | ||
/>, | ||
{ attachTo }, |
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'm not always attaching to the DOM, because it breaks other tests, and is relevant only to test the default focusing functionality.
I'd like us to understand exactly what is happening here. Is it something that could affect other elements? |
The way Then, it captures the This keeps the focus trapped inside the modal while it is opened. The first problem with this is that this logic never took into account that an iframe could be rendered inside the modal, and the default selector to find all focusable elements does not include iframes. The second problem is that, even if we include it, once the focus has transitioned inside the iframe itself, the logic in the hook stops working, probably because the manual There is a bit of speculation in my explanation, and I will have to dig deeper to know all the details, but this seems to be more or less the problem. |
e400d6c
to
203276f
Compare
I've been doing some more testing with the ModalDialog in frontend-shared pattern library, and it's more or less what I described above. Not exactly that anything is getting "out of sync", but the fact that the I have realized that the focus trap works because the modal renders an overlay that doesn't allow you to click anywhere else and incidentally focus other elements outside of the modal, but if you remove the overlay and click somewhere else, you can reproduce the same issue happening with the iframe. If we render an iframe inside the modal itself, there's no way to prevent the user from clicking "outside" the modal, which ends up with a tab sequence that includes the rest of the content from the main frame which is outside (or "behind") the modal. |
I'm exploring some alternative approach to do focus trapping that allows focusing the iframe and its content, while preventing the elements outside the modal to be focused. I'll put this on hold for now. |
Closing in favor of #6187 |
Depends on hypothesis/frontend-shared#1442 and hypothesis/frontend-shared#1443
Closes #6158
Use a
ModalDialog
for the notebook, which brings a few accessibility fixes like havingrole="dialog"
,aria-modal="true"
and focus trap out of the box.This addresses the next points from the accessibility review:
Testing steps
Known issues
The Modal's focus trap causes the focus to be trapped in the close button if you focus out of the iframe. I plan to address this separately as it seems a bit complex.
Considerations
While working on this PR I realized we are only hiding the notebook when closed, instead of fully removing it from the DOM.
At first I thought this was intentional, to avoid multiple loads of the iframe and its contents, but then I realized the iframe has a
key
prop which is intentionally updated every time it is opened, and there's a comment explaining that forces the content to be up to date.Separately, I will check if we could avoid this extra piece of state by just fully removing the notebook from the DOM when closed, but I want to check if A) It doesn't have other side effects and B) it doesn't move us in the wrong direction, assuming the reloading of the iframe is just a workaround for something else, in which case current approach makes it more explicit that this is not the desired behavior long term.
EDIT: We have discussed the above and we are going to keep it as it is now, because the long-term intended approach is to not load the iframe at all if annotations didn't change. Destroying the notebook on close would make this desire less obvious.