Skip to content
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

Modal does not have a focus trap #600 #734

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

rlucke
Copy link
Contributor

@rlucke rlucke commented Jun 24, 2024

add focus trap to modals

fixes #600

@rlucke rlucke self-assigned this Jun 24, 2024
@rlucke rlucke added the type:accessibility This would help impaired users label Jun 24, 2024
Copy link
Contributor

Hi @rlucke
Thank you for contributing to the Opencast Editor.
We noticed that you have not yet filed an Individual Contributor License Agreement. Doing that (once) helps us to ensure that Opencast stays free for all. If you make your contribution on behalf of an institution, you might also want to file a Corporate Contributor License Agreement (giving you as individual contributor a bit more security as well). It can take a while for this bot to find out about new filings, so if you just filed one or both of the above do not worry about this message!
Please let us know if you have any questions regarding the CLA.

Copy link
Contributor

Use docker or podman to test this pull request locally.

Run test server using develop.opencast.org as backend:

podman run --rm -it -p 127.0.0.1:3000:3000 ghcr.io/opencast/opencast-admin-interface:pr-734

Specify a different backend like stable.opencast.org:

podman run --rm -it -p 127.0.0.1:3000:3000 -e PROXY_TARGET=https://stable.opencast.org ghcr.io/opencast/opencast-admin-interface:pr-734

It may take a few seconds for the interface to spin up.
It will then be available at http://127.0.0.1:3000.
For more options you can pass on to the proxy, take a look at the README.md.

Copy link
Contributor

This pull request is deployed at test.admin-interface.opencast.org/734/2024-06-25_09-02-25/ .
It might take a few minutes for it to become available.

Copy link
Contributor

github-actions bot commented Jul 1, 2024

This pull request has conflicts ☹
Please resolve those so we can review the pull request.
Thanks.

Copy link
Member

@Arnei Arnei left a comment

Choose a reason for hiding this comment

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

From my testing this seems to generally work, but there still are some problems. Below is an assortment of observations. Testing done with Firefox 121.

I can escape the trap if I press tab before the modal has finished loading, but that should not constitute a common scenario.

I can escape the "Start Task" modal if i mash tab for long enough. Same with "Recording Details" modal. There might be more, I did not go through all of them.

If anything this PR goes to show that we really want our own Modal wrapper component thingy :D

Out of interest, why did you choose to implement the focus trap yourself instead of using a library like focus-trap-react?

@@ -0,0 +1,37 @@

export const focusTrap = (modalRef: any, focusEneabled: boolean, setFocusEneabled: Function) => {
Copy link
Member

Choose a reason for hiding this comment

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

Eneabled is incorrect spelling. Should be Enabled.

@@ -0,0 +1,37 @@

export const focusTrap = (modalRef: any, focusEneabled: boolean, setFocusEneabled: Function) => {
Copy link
Member

Choose a reason for hiding this comment

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

Would be great if we could avoid any for the modalRef. At least something like React.MutableRefObject<unknown> should work, although I'm actually not sure if that is any better.

@@ -12,6 +13,14 @@ const GroupDetailsModal = ({
groupName
}: any) => {
const { t } = useTranslation();
const closeButtonRef = React.useRef(null);
Copy link
Member

Choose a reason for hiding this comment

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

This ref looks like it is going unused. Did you mean to pass it to focusTrap([...])?


export const focusTrap = (modalRef: any, focusEneabled: boolean, setFocusEneabled: Function) => {
const modalElement = modalRef.current as HTMLElement | null;
const closeButton = document.getElementsByClassName('close-modal')[0] as HTMLElement;
Copy link
Member

Choose a reason for hiding this comment

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

Intuitively I'd say that this should also be a ref that is passed to this function, but maybe that is not reasonable?

const focusableElements = modalElement.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0] as HTMLElement;
Copy link
Member

Choose a reason for hiding this comment

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

Is querySelectorAll guaranteed to return a non-empty list?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:conflicts type:accessibility This would help impaired users
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Modal does not have a focus trap
2 participants