I'm trying to render a tooltip on an element within a Shadow DOM, but for some reason, it doesn't work as expected. The tooltip is rendered correctly on the mouse enter event, but stays visible after the mouse has left the target element.
Here's a code sandbox that demonstrates this issue: https://codesandbox.io/s/holy-rgb-c4qj6
Hovering over the second button renders the tooltip, but it stays even after the mouse has left the button.
@prvnsmpth Do you know why? Any idea of what the fix could be?
I'm still trying to figure out what's happening by looking at the Tooltip implementation. I was hoping that if something was missing in my code sandbox demo, someone would point out what I was doing wrong. I will keep looking and update if I find anything.
@oliviertassinari I think it is because the mouseleave event does not bubble up, and so the retargeted event handler is not able to handle the mouseleave event, and remove the popper from the DOM. I'm not sure if this is the root cause though, still need to take a closer look.
@oliviertassinari Is it possible to use mouseout instead of mouseleave in the Tooltip implementation? That should fix the problem.
I'm not sure we can: https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseleave_event.
I found a hacky solution by sending fake onMouseLeave events when onMouseOut is triggered. It works well with material ui.
PR: https://github.com/spring-media/react-shadow-dom-retarget-events/pull/19
Demo: https://codesandbox.io/embed/react-shadow-dom-retarget-events-onmouseleave-8xl6n
@Thomvaill Thanks for exploring a solution on the react-shadow-dom-retarget-events side. I have tried to replace the mouse leave listener with a mouse out listener. This seems to do the trick:
diff --git a/packages/material-ui/src/Tooltip/Tooltip.js b/packages/material-ui/src/Tooltip/Tooltip.js
index 46cf5bd8b..60084fc29 100644
--- a/packages/material-ui/src/Tooltip/Tooltip.js
+++ b/packages/material-ui/src/Tooltip/Tooltip.js
@@ -253,8 +253,13 @@ function Tooltip(props) {
handleBlur(event);
}
- if (event.type === 'mouseleave' && childrenProps.onMouseLeave) {
- childrenProps.onMouseLeave(event);
+ if (event.type === 'mouseout' && childrenProps.onMouseOut) {
+ childrenProps.onMouseOut(event);
+ }
+
+ // Reproduces a mouse leave like event.
+ if (event.type === 'mouseout' && event.currentTarget.contains(event.relatedTarget)) {
+ return;
}
clearTimeout(enterTimer.current);
@@ -337,7 +342,7 @@ function Tooltip(props) {
if (!disableHoverListener) {
childrenProps.onMouseOver = handleEnter;
- childrenProps.onMouseLeave = handleLeave;
+ childrenProps.onMouseOut = handleLeave;
}
if (!disableFocusListener) {
@@ -348,7 +353,7 @@ function Tooltip(props) {
const interactiveWrapperListeners = interactive
? {
onMouseOver: childrenProps.onMouseOver,
- onMouseLeave: childrenProps.onMouseLeave,
+ onMouseOut: childrenProps.onMouseOut,
onFocus: childrenProps.onFocus,
onBlur: childrenProps.onBlur,
}
However, I haven't stress test it 馃.
I'm curious, what's the motivation for rendering the tooltip in a shadow DOM?
I'm closing, it's probably not very important. If somebody want to apply the above patch, he is welcome.
I'm curious, what's the motivation for rendering the tooltip in a shadow DOM?
One can be wrapping a microfrontend in a web component. Can I submit a PR with this patch?
I'm curious, what's the motivation for rendering the tooltip in a shadow DOM?
In my case I was developing a Chrome extension, which inserted shadow DOM into the current page ;)
Why shadow DOM? To avoid conflict with current page CSS.
@Thomvaill +1. I too ran into this issue while building a chrome extension.
+1 I ran into the same issue in shadow dom.
Had this issue while wrapping a webcomponent microfrontend.
Most helpful comment
+1 I ran into the same issue in shadow dom.