Lecstor's Blog

React does not fire onMouseLeave events on a disabled button

December 22, 2018

Posting as this was decently difficult to diagnose while researching and testing 3rd party popover/tooltip components.

The button component I needed an onHover tooltip for is responsive via either react-responsive or plain old media queries.

The responsive options were wrapped in a React.Fragment so there were also issues with the tooltip components augmenting the first option even when the second was displayed (unconfirmed if this was only with plain media queries).

Swapping React.Fragment for a plain div changed the results, but did not solve the problem, making the issue more difficult to debug.

In the end I think the best solution will be to simply fake the disabled state of the button instead of actually disabling the html element.

Demo on CodeSandbox

References:

import React from "react";
import ReactDOM from "react-dom";

function log(who) {
  return () => console.log(who);
}

function App() {
  return (
    <div className="App">
      <h1>Hello Button</h1>
      <p>
        React will not fire onMouseLeave events for a disabled button (although
        it does fire onMouseEnter)
      </p>
      <p>Open the CodeSandbox console to see logging</p>
      <div style={{ margin: "3rem" }}>
        Works as intended{" "}
        <button onMouseEnter={log("enter")} onMouseLeave={log("leave")}>
          Button
        </button>
      </div>
      <div style={{ margin: "3rem" }}>
        No onMouseLeave{" "}
        <button
          disabled
          onMouseEnter={log("disabled enter")}
          onMouseLeave={log("disabled leave")}
        >
          Disabled Button
        </button>
      </div>
      <div style={{ margin: "3rem" }}>
        Events on parent div, works sometimes
        <div
          style={{ border: "1px solid blue" }}
          onMouseEnter={log("div enter")}
          onMouseLeave={log("div leave")}
        >
          <button disabled>Div'd Disabled Button</button>
        </div>
      </div>
      <div style={{ margin: "3rem" }}>
        Events on parent div with padding, works more often (dependant on mouse
        move speed)
        <div
          style={{ padding: "1px", border: "1px solid blue" }}
          onMouseEnter={log("div 2 enter")}
          onMouseLeave={log("div 2 leave")}
        >
          <button disabled>Div'd Disabled Button 2</button>
        </div>
      </div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Jason Galea

Written by Jason Galea from Cairns, Australia.

Full Stack developer specialising in React and NodeJS.

LinkedIn | Github | StackOverflow | Twitter