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

onMouseLeave can be unreliable in Chrome #4492

Closed
petehunt opened this issue Jul 26, 2015 · 25 comments
Closed

onMouseLeave can be unreliable in Chrome #4492

petehunt opened this issue Jul 26, 2015 · 25 comments

Comments

@petehunt
Copy link
Contributor

See this jsfiddle: https://jsfiddle.net/tvxderw3/

In Chrome, as you quickly move your mouse up and down the list, you'll notice that some get stuck in the hover state. This works fine in Safari, and works in Chrome if you use a stable key between the hover states. I think mouseout somehow isn't firing if the underlying DOM node is replaced by a new one in the same tick, but it's odd that this is a Chrome-only bug.

@sophiebits
Copy link
Collaborator

Didn't you write React?

@sophiebits
Copy link
Collaborator

Best guess: the top-level onMouseOut doesn't fire on the removed node (which is basically what you said, sorry).

@waldreiter
Copy link
Contributor

@petehunt

This works fine in Safari

I see the bug in Safari as well, version 8.0.7. In Firefox it happens too, but not so often.

@syranide
Copy link
Contributor

FYI this happens without React as well. https://jsfiddle.net/ahf3tay5/

@sophiebits
Copy link
Collaborator

Well that's just lovely. Time to file a Chrome bug?

@syranide
Copy link
Contributor

@spicyj It's in IE too, perhaps this is actually a weird spec thing?

@pswai
Copy link

pswai commented Oct 3, 2015

@syranide I have tried with pure JS and it works fine (tested in Mac Chrome) http://jsfiddle.net/2gmzzzv1/1/

@syranide
Copy link
Contributor

syranide commented Oct 3, 2015

@pswai You're testing a different scenario, my fiddle shows that this is not a problem with the React event system, it's a "problem" with browser behavior when the hovered nodes are replaced/removed.

@pswai
Copy link

pswai commented Oct 3, 2015

@syranide Ah you are right. Thanks for pointing that out.

@pswai
Copy link

pswai commented Oct 3, 2015

@henriquezago
Copy link

I'm also having troubles with this event, tested on Chrome, Firefox (stable) and Edge. It only worked fine on Firefox nightly.

It fires the onMouseEnter just fine, but it almost never works for the onMouseLeave event. There is no way at all to use this Synthetic Event.

@gaearon
Copy link
Collaborator

gaearon commented Oct 3, 2017

@henlz Perhaps it's time to file a new issue with a reproducing example? This one is pretty stale, and it's hard to say if they're even related or not.

@henriquezago
Copy link

@gaearon You're right. I will create one with all the details and steps to reproduce it for a better discussion.

@gaearon
Copy link
Collaborator

gaearon commented Oct 3, 2017

I’ll close this one as it’s unlikely we’ll make meaningful progress on an issue from 2015.

@gaearon gaearon closed this as completed Oct 3, 2017
@oyeanuj
Copy link

oyeanuj commented Apr 27, 2018

@henlz Is there an issue you created for this somewhere? Just ran into this as well :/

@WillSquire
Copy link

Is there a workaround for this?

@flackr
Copy link

flackr commented May 30, 2018

I investigated this issue and it seems that Chrome and Edge not firing mouseleave on removed DOM nodes is correct according to the UI Events spec:

If the event target (e.g. the target element) is removed from the DOM during the mouse events sequence, the remaining events of the sequence MUST NOT be fired on that element.

I filed bugs on firefox and safari for this incorrect behavior.

@kevin-king
Copy link

Also just ran into this issue. Still investigating workarounds. Anyone find a workaround? Will post back if I find a good way to fix.

@DamianDobrev
Copy link

I managed to "fix" this. I'm doing two things:

  1. Added the listener to element which is not display: inline;, rather block/inline-block.
  2. Added pointer-events: none to any containers of SVGs inside the element with the listener.

Seems to work fine now, the event is fired properly. I do not know why though.

@KevinGrant12
Copy link

@DamianDobrev Thank you! What an odd problem. I have a button with child SVG's being animated and this was a 4 day headbanger that I finally tracked to here! It was simply a matter of disabling the pointer events on the child svg's.

@yardenapp
Copy link

I fixed this by invalidating the hover state between renders

// Inside your component
const divRef = useRef();
const [hovered, setHovered] = useState();
 
if(hovered && divRef.current && divRef.current.matches(':hover') === false)
    setHovered(false);

return (
    <div ref={divRef} onMouseEnter={()=>setHovered(true)} onMouseLeave={()=>setHovered(false)}/>
)

@cory-vade
Copy link

I managed to "fix" this. I'm doing two things:

  1. Added the listener to element which is not display: inline;, rather block/inline-block.
  2. Added pointer-events: none to any containers of SVGs inside the element with the listener.

Seems to work fine now, the event is fired properly. I do not know why though.

Does anyone actually understand the root cause of this?

@AKclown
Copy link

AKclown commented Dec 19, 2022

I managed to "fix" this. I'm doing two things:

  1. Added the listener to element which is not display: inline;, rather block/inline-block.
  2. Added pointer-events: none to any containers of SVGs inside the element with the listener.

Seems to work fine now, the event is fired properly. I do not know why though.

Thanks a lot, this is very helpful for me

facebook-github-bot pushed a commit to facebook/sapling that referenced this issue May 1, 2023
Summary:
Kind of a subtle issue here. If you hover on the Pull button long enough to see the tooltip, then click pull, then wait for the tooltip content to change (add "Pull is currently running.") it will no longer detect onMouseLeave and so the tooltip will not auto-dismiss anymore.

This seems to be a quirk of the browser, perhaps related to react synthetic events...? Kind of difficult to attribute exactly, but other people see the same kind of issue: facebook/react#4492

It seems if we add our listener in a layout effect instead of adding it directly via react `onMouseLeave` prop passed ot the div, it keeps the same listener on the DOM node and that means the mouseLeave continues being detected.

Reviewed By: quark-zju

Differential Revision: D45418402

fbshipit-source-id: a1fe0d063f74f4559a75b68177d4828d0f7d8d80
@danny-dang
Copy link

I fixed this by invalidating the hover state between renders

// Inside your component
const divRef = useRef();
const [hovered, setHovered] = useState();
 
if(hovered && divRef.current && divRef.current.matches(':hover') === false)
    setHovered(false);

return (
    <div ref={divRef} onMouseEnter={()=>setHovered(true)} onMouseLeave={()=>setHovered(false)}/>
)

Thank you. This solution works like a champ

@sun-rhythms
Copy link

Referen

Helped me! Thanks!

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

No branches or pull requests