-
Notifications
You must be signed in to change notification settings - Fork 24
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(react): remove focus-trap-react replacing with internally managed focus traps #1730
Conversation
This pull request is automatically being deployed by Amplify Hosting (learn more). |
if (!show || !dialogRef.current) return; | ||
|
||
isolatorRef.current = new AriaIsolate(dialogRef.current); | ||
setTimeout(focusHeading); |
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.
nit - this use of setTimeout
could probably benefit from a comment (I assume this is to wait for the dialog to be rendered, if so there may be a way to avoid setTimeout use)
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, but I wish I remembered why as it's been like this since it's initial implementation:
cauldron/packages/react/src/components/Dialog/index.tsx
Lines 65 to 66 in eb5def1
this.attachEventListeners(); | |
this.attachIsolator(() => setTimeout(this.focusHeading)); |
I'm taking an educated guess that it's queuing the focus to be on the next tick to prevent focus conflicts. We can add that as a comment if you feel that's useful?
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.
Looks good to me. I left a couple of nits. I'm also wondering if we should document anything about not using iframes within things that need focus traps as it could mess with the focus trap code (if, for example, the first tab stop in a dialog is within an iframe)
Co-authored-by: Harris Schneiderman <schne324@gmail.com>
I'm not following 100%. I just tested an alert with an iframe inside of it and it works as expected (since we focus the header by default) and focus works exactly as you would expect. Is there a particular edge case scenario you would be looking to cover? |
I was making an assumption that funky things could happen because we have this code: const focusableElements = Array.from(
targetElement?.querySelectorAll(focusable) || []
) as HTMLElement[]; and any focusable elements that are within an iframe would not be captured in that if (focusableElements.length && eventTarget === startGuard) {
focusableElements.reverse()[0]?.focus();
return;
} else if (focusableElements.length && eventTarget === endGuard) {
focusableElements[0]?.focus();
return;
} the first and last elements in focusable could be, in reality, within an iframe but in this array they are not captured at all |
Ah right. With that code there, the focusable elements would only really be applicable for the first or last element (to determine where the next focus needs to go). In my test case I still had surrounding elements within the iframe and it works as expected. So this would be a bit of an edge case where the last or first focusable element was within an iframe. I feel that's an acceptable outcome for us, but I'm not sure how we want to take note of it. The majoritive use case would be working within a single document context. |
closes #1703
Any existing components that were utilizing
focus-trap-react
should now be using the internaluseFocusTrap
hook. Some small refactors had to take place to accommodate the new hook, but otherwise the functionality should be identical.