-
-
Notifications
You must be signed in to change notification settings - Fork 215
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
Focus is trapped inside drawers when always open even with modal=false #497
Comments
This has been bugging me for weeks. With my quick investigation, it looks like it's an issue with Radix and not this library. |
Add this to your Component that renders your Drawer, and it will bypass the focus trap // Hack to remove focus trap
useLayoutEffect(() => {
document.addEventListener('focusin', e => e.stopImmediatePropagation());
document.addEventListener('focusout', e => e.stopImmediatePropagation());
}, []); |
Using the snippet of code inside my component that renders the Drawer does not fix the issue at all for me. The focus still gets trapped inside the drawer and I cannot focus on anything else in the page. Is this workaround missing a critical bit of information? |
My fix was for focusing on input elements outside the drawer. Below is a fix for clicking on anything outside the drawer that you can try useEffect(() => {
if (isOpen) {
// Pushing the change to the end of the call stack
const timer = setTimeout(() => {
document.body.style.pointerEvents = '';
}, 0);
return () => clearTimeout(timer);
} else {
document.body.style.pointerEvents = 'auto';
}
}, [isOpen]); |
I'm confused, the issue talks about a problem with not being able to use keyboard navigation to tab out of the Drawer's focus trap, not about clicking interactable elements outside of the Drawer's content. I have no problem interacting with the rest of the page, I simply cannot navigate outside of the drawer's inputs with keyboard navigation, and the first snippet that supposedly should be a workaround for this still does not fix that issue for me. Am I missing something? |
If I understand the Radix component correctly, the issue here is that we never send the How Vaul's Drawer implementation calls <DialogPrimitive.Root
defaultOpen={defaultOpen}
onOpenChange={(open) => {
if (!dismissible && !open) return;
if (open) {
setHasBeenOpened(true);
} else {
closeDrawer(true);
}
setIsOpen(open);
}}
open={isOpen}
> The definition of const Dialog: React.FC<DialogProps> = (props: ScopedProps<DialogProps>) => {
const {
__scopeDialog,
children,
open: openProp,
defaultOpen,
onOpenChange,
modal = true,
} = props;
const triggerRef = React.useRef<HTMLButtonElement>(null);
const contentRef = React.useRef<DialogContentElement>(null);
const [open = false, setOpen] = useControllableState({
prop: openProp,
defaultProp: defaultOpen,
onChange: onOpenChange,
});
return (
<DialogProvider
scope={__scopeDialog}
triggerRef={triggerRef}
contentRef={contentRef}
contentId={useId()}
titleId={useId()}
descriptionId={useId()}
open={open}
onOpenChange={setOpen}
onOpenToggle={React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen])}
modal={modal}
>
{children}
</DialogProvider>
);
}; The definition of const DialogContent = React.forwardRef<DialogContentElement, DialogContentProps>(
(props: ScopedProps<DialogContentProps>, forwardedRef) => {
const portalContext = usePortalContext(CONTENT_NAME, props.__scopeDialog);
const { forceMount = portalContext.forceMount, ...contentProps } = props;
const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
return (
<Presence present={forceMount || context.open}>
{context.modal ? (
<DialogContentModal {...contentProps} ref={forwardedRef} />
) : (
<DialogContentNonModal {...contentProps} ref={forwardedRef} />
)}
</Presence>
);
}
); How trapFocus={context.open} How trapFocus={false} So clearly, with the way this is setup right now, it's kind of obvious why the focus is always trapped even when we set |
So after searching a bit as far as I understand the modal property was removed in #424, but I'm not entirely sure why... As it clearly breaks non-modal drawers functionality, could we see about adding it back? Or investigate a way to bypass this focus trap? |
When a Drawer is always open and non-dismissible, for example when using snapPoints, tabbing into the drawer or nested drawers will trap the focus and you won't be able to tab back into the rest of the page. Even when using
modal={false}
.Repro: https://codesandbox.io/p/devbox/85dwhz
Tabbing the page will result in focus on:
Tabbing will now be stuck in a loop between main and secondary drawer. (This also happens with only 1 drawer, nested drawers only to debug my specific case.)
Is there a way to get around this behavior? Or is it an issue with Radix dialogs and/or vaul's handling of
modal=false
?The text was updated successfully, but these errors were encountered: