primitives icon indicating copy to clipboard operation
primitives copied to clipboard

[Dialog] Pointer down on `Overlay` scrollbar closes dialog (impossible to grab scroll)

Open lesha1201 opened this issue 3 years ago • 5 comments

Bug report

In Outer Scrollable story, Dialog Overlay has a scroll but Dialog is closed when clicking on Overlay's scrollbar which makes it impossible to scroll using left mouse button.

Current Behavior

Dialog is closed when clicking on Overlay's scrollbar.

Expected behavior

Dialog isn't closed when clicking on Overlay's scrollbar and it's possible to scroll by holding left mouse button.

Reproducible example

https://user-images.githubusercontent.com/10157660/160576823-63fba34c-4bb4-452e-a90b-7bbe4950c5ba.mp4

Your environment

Software Name(s) Version
Radix Package(s) dialog, dismissable-layer 0.1.7
React n/a 17
Browser Chrome, Firefox 99.0.4844.84, 99.0b8

lesha1201 avatar Mar 29 '22 09:03 lesha1201

there is an onPointerDownOutside event on Dialog.Content that you can prevent if wish to prevent clicking outside from closing https://www.radix-ui.com/docs/primitives/components/dialog#content

jjenzz avatar Mar 29 '22 11:03 jjenzz

@jjenzz I don't want to prevent clicking outside from closing. I want to preserve it and make it possible to scroll using left mouse button.

lesha1201 avatar Mar 29 '22 12:03 lesha1201

headless seems to be running into the same problem 😅

https://twitter.com/adamwathan/status/1530666459545931776

BrianHung avatar Jun 01 '22 06:06 BrianHung

As @BrianHung already pointed out, it is not really impossible to identify a scrollbarclick by the event target or something.

As a workaround I am using the following handler on Dialog.Content:

onPointerDownOutside={(e) => {
  const currentTarget = e.currentTarget as HTMLElement;

  if (e.detail.originalEvent.offsetX > currentTarget.clientWidth) {
    e.preventDefault();
  }
}}

josias-r avatar Jul 28 '22 14:07 josias-r

@josias-r,

This is really clever! I was wondering if we would be able to do it by location rather and that's exactly what you've done here.

I think we should be able to use something like this as a solution internally. We'd have to ensure we cater for RTL, and to do this in only certain conditions are met, but this is a good start.

Thanks! 🙏

benoitgrelard avatar Aug 01 '22 15:08 benoitgrelard

This is my solution to prevent clicks on the 1password button from closing the dialog when clicked. The 1password extension absolutely positions this button over an input within the dialog. The dialog is positioned in the center of the viewport, so clientX/clientY is used instead of offsetX/offsetY.

 <Dialog.Content
  ref={contentRef}
  onPointerDownOutside={(e) => {
    if (!contentRef.current) return
    const contentRect = contentRef.current.getBoundingClientRect()
    // Detect if click actually happened within the bounds of content.
    // This can happen if click was on an absolutely positioned element overlapping content,
    // such as the 1password extension icon in the text input.
    const actuallyClickedInside =
      e.detail.originalEvent.clientX > contentRect.left &&
      e.detail.originalEvent.clientX < contentRect.left + contentRect.width &&
      e.detail.originalEvent.clientY > contentRect.top &&
      e.detail.originalEvent.clientY < contentRect.top + contentRect.height
    if (actuallyClickedInside) {
      e.preventDefault()
    }
  }}
> 
  content here 
</Dialog.Content>

gragland avatar Nov 17 '22 19:11 gragland