fix(dialog): overlay scroll for large content
This PR fixes the scroll block problem on dialog component.
I added some classes to DialogPrimitive.Overlay to keep content centered and moved DialogPrimitive.Content into DialogOverlay which worked in my case.
Also this is described in docs here
This problem is also described in some issues here. https://github.com/shadcn/ui/issues/16 and https://github.com/shadcn/ui/pull/18
And this PR is improved solution for both large and small dialog content. https://github.com/shadcn/ui/pull/472
@aaliboyev is attempting to deploy a commit to the shadcn-pro Team on Vercel.
A member of the Team first needs to authorize it.
I do see a scrollbar, but when I try to use the scrollbar the dialog closes.
A simple workaround that worked for me was wrapping the content inside a <div> with overflow-y-auto and max-h-full (tailwind classes). I hope this helps anyone who might be looking for a similar functionality.
For anyone facing the same issue I had to do some tweaks to @aaliboyev's code.
"use client";
import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import { useLockBodyScroll } from "react-use";
import { cn } from "@/lib/utils";
const Dialog = ({ open, ...props }: DialogPrimitive.DialogProps) => {
useLockBodyScroll(open);
return <DialogPrimitive.Root open={open} {...props} />;
};
Dialog.displayName = DialogPrimitive.Dialog.displayName;
const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = ({ className, children, ...props }: DialogPrimitive.DialogPortalProps) => (
<DialogPrimitive.Portal className={cn(className)} {...props}>
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">{children}</div>
</DialogPrimitive.Portal>
);
DialogPortal.displayName = DialogPrimitive.Portal.displayName;
const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 overflow-y-auto py-3 grid place-items-center bg-black/20 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
className
)}
{...props}
/>
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay>
<DialogPrimitive.Content
ref={ref}
className={cn(
"relative z-50 gap-4 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-5 w-5" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogOverlay>
</DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
I did the following changes:
- Add the
relativeclass to theDialogContentso theXstayed in place - Added
py-3to the theDialogOverlayso it had a bit of breathing room on smaller screens - I don't know why but the body scroll locking does not work with this setup so I had to modify the
Dialogroot