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

fix(dialog): overlay scroll for large content #478

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

Conversation

aaliboyev
Copy link

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.
#16 and #18

And this PR is improved solution for both large and small dialog content.
#472

@vercel
Copy link

vercel bot commented May 29, 2023

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

A member of the Team first needs to authorize it.

@hussamkhatib
Copy link

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

@syclone
Copy link

syclone commented Jun 18, 2023

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.

@vimtor
Copy link

vimtor commented Jun 22, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants