How jQuery hover Combines mouseenter and mouseleave

The jQuery hover() method is a shorthand convenience method designed to bind event handlers for when a user's cursor moves over and leaves an element. Instead of requiring developers to bind separate listeners for entering and exiting, hover() combines the mouseenter and mouseleave events into a unified syntax. This article explains the internal mechanics of how hover() ties these two events together, why these specific events are used instead of mouseover and mouseout, and how to implement the method correctly.

The Syntax and Mapping

The hover() method accepts either one or two function arguments:

$(selector).hover(handlerIn, handlerOut);

When two functions are passed, jQuery internally maps the first function (handlerIn) to the mouseenter event, and the second function (handlerOut) to the mouseleave event.

Under the hood, calling:

$("#target").hover(
  function() {
    $(this).addClass("active");
  },
  function() {
    $(this).removeClass("active");
  }
);

is strictly equivalent to:

$("#target")
  .on("mouseenter", function() {
    $(this).addClass("active");
  })
  .on("mouseleave", function() {
    $(this).removeClass("active");
  });

If only a single function is passed to hover(), jQuery binds that identical callback function to both the mouseenter and mouseleave events:

$("#target").hover(function() {
  $(this).toggleClass("active");
});

Why jQuery Uses mouseenter and mouseleave

jQuery specifically binds mouseenter and mouseleave rather than the traditional native DOM events mouseover and mouseout to prevent bubbling issues.

The traditional mouseover and mouseout events bubble up the DOM tree. If an element has child elements, moving the cursor over a child element triggers a mouseout event on the parent, immediately followed by a mouseover event on the child that bubbles back up to the parent. This behavior often causes unwanted flickering when applying hover states or animations.

In contrast, mouseenter and mouseleave do not bubble. A mouseenter event fires only when the pointer moves inside the bound element from outside of it, and mouseleave fires only when the pointer moves completely outside of the bound element. By utilizing these non-bubbling events, the hover() method ensures smooth execution without false exits caused by nested child elements.