ui icon indicating copy to clipboard operation
ui copied to clipboard

fix(dialog): overlay scroll for large content

Open aaliboyev opened this issue 2 years ago • 6 comments

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 avatar May 29 '23 02:05 aaliboyev

@aaliboyev is attempting to deploy a commit to the shadcn-pro Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar May 29 '23 02:05 vercel[bot]

I do see a scrollbar, but when I try to use the scrollbar the dialog closes.

hussamkhatib avatar Jun 14 '23 17:06 hussamkhatib

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.

OmarRobinson avatar Jun 18 '23 03:06 OmarRobinson

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:

  1. Add the relative class to the DialogContent so the X stayed in place
  2. Added py-3 to the the DialogOverlay so it had a bit of breathing room on smaller screens
  3. I don't know why but the body scroll locking does not work with this setup so I had to modify the Dialog root

vimtor avatar Jun 22 '23 10:06 vimtor