tailwindlabs / headlessui

Completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS.
https://headlessui.com
MIT License
25.69k stars 1.06k forks source link

[Bug]: Dialog blocks click event listener #834

Closed andresespinosapc closed 2 years ago

andresespinosapc commented 2 years ago

What package within Headless UI are you using?

@headlessui/vue

What version of that package are you using?

1.4.1

What browser are you using?

Chrome

Reproduction repository

https://codesandbox.io/s/bug-headless-ui-dialog-click-outside-8n3jh

Describe your issue

Click event listener is not emitted on dialogs.

The problem with this is that I'm trying to make a dropdown that closes when clicking outside. To do that I want to add a global event listener for the click event, but it's not being triggered.

syropian commented 2 years ago

Also running into this, any workarounds we could use @RobinMalfait ?

knoefel commented 2 years ago

I'm having the same problem for react.

hamza512b commented 2 years ago

The Dialog component blocks click event by default: Vue: https://github.com/tailwindlabs/headlessui/blob/6fc28c610f14a3ab88a425cf97a67cee9bcb8e71/packages/%40headlessui-vue/src/components/dialog/dialog.ts#L224-L226

React: https://github.com/tailwindlabs/headlessui/blob/6fc28c610f14a3ab88a425cf97a67cee9bcb8e71/packages/%40headlessui-react/src/components/dialog/dialog.tsx#L285-L295

And unfortunately we can not override it, because these default props are destructed after the actual props we pass to the component: Vue: https://github.com/tailwindlabs/headlessui/blob/6fc28c610f14a3ab88a425cf97a67cee9bcb8e71/packages/%40headlessui-vue/src/components/dialog/dialog.ts#L250

React: https://github.com/tailwindlabs/headlessui/blob/6fc28c610f14a3ab88a425cf97a67cee9bcb8e71/packages/%40headlessui-react/src/components/dialog/dialog.tsx#L324

For now as work around, I have used mousedown instead of click event.

RobinMalfait commented 2 years ago

Hey! Thank you for your bug report! Much appreciated! 🙏

This is done on purpose. You should think of a Dialog as a separate page where you shouldn't interact with things behind it. Putting an event listener on the document is technically interacting with things behind the Dialog.

If you want to implement a dropdown that closes when you click outside, then you should be able to use our Menu component that has this functionality outside of the box.

Here is an example: https://codesandbox.io/s/bug-headless-ui-dialog-click-outside-forked-21t72y?file=/src/App.vue

psychonetic commented 2 years ago

Can we please reopen this? Because there are still cases, there you have the same issue. For my case we show some text which might contain links (text created of wysiwyg editor). So if the user clicks on a link, which is an external domain a popup should show up. But that's not possible, because of the current behaviour. As mentioned mousedown would work, but that's more complicated then it could be.

At least this behaviour should be mentioned in the documentation.

What do you think?

RobinMalfait commented 2 years ago

@psychonetic can you install the insiders build to see if that fixes things for you? If not, please open a new issue with a reproduction repo / codesandbox attached.

idesignzone commented 1 year ago

I have the same issue. Click event is blocked within dialog. In my case I have a Click event that will hide or show some div within the dialog itself. How am I supposed to handle this? And I don't understand why it is done on purpose! Like no one will ever need a click event within the dialog?

Shusanta commented 1 year ago

Agreed. Reviving this thread

binaryfire commented 1 year ago

We’re in the same boat as @idesignzone. This is very limiting design decision IMHO. And it’s not in line with how most established component libraries do it.

Shusanta commented 1 year ago

to solve this in react, wrap your other dialog you want clickable in a portal

neontuna commented 7 months ago

We're also having issues due to this - specifically we use ahoy JS to track some click events in Vue. This is enabled at the doc/window level and now I need to figure out a work around inside our dialog components

jackocnr commented 6 months ago

@RobinMalfait I echo the concerns of others in this thread - calling event.stopPropagation on all click events seems unnecessary, and is breaking how the intl-tel-input plugin works - basically any popup within the dialog is unclosable because the click-off-to-close listener is on the root document.documentElement and so never gets fired. In my experience, the normal way to handle this dialog click management situation, is to have the click listener on the grey background element, and check within the handler function that the element that was clicked on was indeed that grey element (hence ignoring any clicks within the dialog itself), if that makes sense? Is there a reason why this is not sufficient in this case? Thanks for your time.

alexbusu commented 2 months ago

@RobinMalfait would you please be kind enough to tell what are the reasons to do event.stopPropagation() in a listener put on document? What's the benefit from putting it on document instead of the gray fixed-positioned overlay of a dialog?