JavaScript Element mouseleave Event

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
DOM event
Instance event

What You’ll Learn

The mouseleave event fires when a pointing device moves out of an element. Learn addEventListener vs onmouseleave, how it differs from mouseout, the mouseenter pair, CSS :hover-like cleanup, and five try-it labs.

01

Kind

Instance event

02

Type

MouseEvent

03

When

Pointer leaves

04

Handler

onmouseleave

05

Bubbles?

No

06

Status

Baseline widely available

Introduction

mouseleave answers: “Did the pointer just leave this element and all of its descendants?” Pair it with mouseenter and you get JS hover enter/exit signals similar to CSS :hover.

Unlike mouseout, mouseleave does not bubble and fires only after the pointer has left the element and all descendants. That makes it friendlier for card/hover UI where you want one clean exit, not a burst of out events while moving among children.

💡
Beginner tip

“Leaving” follows the DOM tree, not only the painted box. Moving into a visually nested sibling can fire mouseleave on the outer element even if the pointer still looks inside the outer element’s painted area.

Understanding mouseleave

An instance event that answers: “Did the pointer just leave this element?”

  • Fires when the pointer moves out of the element and all descendants.
  • Does not bubble — stays on the element that was left.
  • Descendants — moving among children does not fire leave on the parent.
  • Pairmouseenter when the pointer enters.
  • Not fired when the element is removed/replaced in the DOM (MDN).
  • Baseline Widely available on MDN (since July 2015).

📝 Syntax

Use the event name with addEventListener, or set the handler property:

JavaScript
addEventListener("mouseleave", (event) => { });

onmouseleave = (event) => { };

Event type

A MouseEvent (inherits from UIEvent and Event).

Handy properties

PropertyMeaning
clientX / clientYPointer position in the viewport
relatedTargetThe secondary target (where the pointer came from), if any
targetThe element that was left
ctrlKey / shiftKey / …Modifier keys at enter time

⚖️ mouseleave vs mouseout

Featuremouseleavemouseout
Bubbles?NoYes
Moving among descendantsDoes not fire on the parentFires / bubbles as you move
Best forWhole-component hover exitDelegation / bubbling paths
Enter twinmouseentermouseover
⚠️
Performance note (MDN)

Leaving a deep hierarchy can send many mouseleave events (one per ancestor). Prefer mouseout when you need a single bubbling path, or measure cost if you attach leave listeners widely.

⚡ Quick Reference

GoalCode / note
Listenel.addEventListener("mouseleave", fn)
Handler propertyel.onmouseleave = fn
Enter pairmouseenter
CSS cousin:hover
Bubbling twinmouseout (vs mouseover)
MDN statusBaseline Widely available

🔍 At a Glance

Four facts to remember about mouseleave.

Event type
MouseEvent

UIEvent + Event

Means
entered

Pointer moved in

Bubbles
false

Unlike mouseover

Baseline
yes

Widely available

Examples Gallery

Examples follow MDN Element: mouseleave event. Move the pointer into and out of the stage elements.

📚 Getting Started

MDN-style enter/leave logging and the handler property.

Example 1 — Restore Border on Leave (MDN)

Highlight on enter; use mouseleave to restore the border and log the exit.

JavaScript
let enterEventCount = 0;
let leaveEventCount = 0;
const mouseTarget = document.getElementById("mouseTarget");
const unorderedList = document.getElementById("unorderedList");

mouseTarget.addEventListener("mouseenter", () => {
  mouseTarget.style.border = "5px dotted orange";
  enterEventCount++;
  addListItem("This is mouseenter event " + enterEventCount + ".");
});

mouseTarget.addEventListener("mouseleave", () => {
  mouseTarget.style.border = "1px solid #333333";
  leaveEventCount++;
  addListItem("This is mouseleave event " + leaveEventCount + ".");
});

function addListItem(text) {
  const li = document.createElement("li");
  li.textContent = text;
  unorderedList.appendChild(li);
}
Try It Yourself

How It Works

Leave fires once when the pointer exits the whole target—moving among list items inside does not spam leave.

Example 2 — onmouseleave Property

Clear a hover class when the pointer leaves.

JavaScript
const card = document.getElementById("card");
const out = document.getElementById("out");

card.onmouseenter = () => {
  card.classList.add("is-hot");
  out.textContent = "entered";
};

card.onmouseleave = () => {
  card.classList.remove("is-hot");
  out.textContent = "left";
};
Try It Yourself

How It Works

Prefer addEventListener when you need multiple listeners or easy removal.

📈 Compare, Cleanup & Destination

Count mouseleave vs mouseout, hide previews on leave, and read relatedTarget.

Example 3 — Count mouseleave vs mouseout

Move among children and compare how often each event fires on the parent.

JavaScript
const parent = document.getElementById("parent");
const out = document.getElementById("out");
let leaveCount = 0;
let outCount = 0;

parent.addEventListener("mouseleave", () => {
  leaveCount++;
  render();
});

parent.addEventListener("mouseout", () => {
  outCount++;
  render();
});

function render() {
  out.textContent = "mouseleave=" + leaveCount + " mouseout=" + outCount;
}
Try It Yourself

How It Works

mouseout fires as you move among descendants; mouseleave waits until you leave the whole parent.

Example 4 — Hide Preview on Leave

Show a tip on enter; hide it cleanly with mouseleave.

JavaScript
const card = document.getElementById("card");
const tip = document.getElementById("tip");

card.addEventListener("mouseenter", () => {
  tip.hidden = false;
  tip.textContent = "Preview details…";
});

card.addEventListener("mouseleave", () => {
  tip.hidden = true;
  tip.textContent = "";
});
Try It Yourself

How It Works

Because leave ignores child moves, the tip does not flicker while the pointer travels inside the card.

Example 5 — Where Did the Pointer Go?

Use relatedTarget on leave to see the destination element when available.

JavaScript
const outer = document.getElementById("outer");
const out = document.getElementById("out");

outer.addEventListener("mouseleave", (event) => {
  out.textContent =
    "left outer (to " +
    ((event.relatedTarget && event.relatedTarget.id) || "outside") +
    ")";
});

outer.addEventListener("mouseenter", () => {
  out.textContent = "inside outer";
});
Try It Yourself

How It Works

relatedTarget is the secondary target (where the pointer went) when the engine provides it.

🚀 Common Use Cases

  • Hide tooltips / previews when the pointer leaves a card.
  • Remove highlight classes that were added on mouseenter.
  • Cancel hover-driven prefetch timers on exit.
  • Close hover menus only after leaving the whole control.
  • Teach the difference between bubbling mouseout and non-bubbling leave.

🔧 How It Works

1

mouseenter

Pointer entered the element; hover UI may turn on.

Enter
2

Move among children

Parent does not get mouseleave yet.

Stable
3

Exit subtree

Pointer leaves the element and all descendants.

Exit
4

mouseleave

Clean up hover UI, timers, and classes.

📝 Notes

  • MDN: Baseline Widely available (since July 2015) — no Deprecated / Experimental / Non-standard banner.
  • Does not bubble; use mouseout when you need delegation from a parent.
  • Not fired when the element is removed or replaced in the DOM.
  • For touch UIs, hover leave is not always available; design a non-hover path too.
  • Related learning: mouseenter, mousedown, addEventListener(), JavaScript hub.

Browser Support

mouseleave is marked Baseline Widely available on MDN (since July 2015). Logos use the shared browser-image-sprite.png sprite from this project. Non-bubbling leave behavior is consistent across modern engines.

Baseline · Widely available

Element mouseleave

Fires when the pointer leaves an element and its descendants; pair with mouseenter for hover UI.

Full Widely available
Google Chrome Full support
Yes
Mozilla Firefox Full support
Yes
Apple Safari Full support
Yes
Microsoft Edge Full support
Yes
Opera Full support
Yes
Internet Explorer Supported
Yes
mouseleave Baseline

Bottom line: Great for component hover exit. Prefer mouseout for bubbling/delegation, and always clean up leave state.

Conclusion

mouseleave is the non-bubbling “pointer left this element” signal. Pair it with mouseenter for stable hover UI, and reach for mouseout when bubbling or delegation matters.

Continue with mousemove, mouseenter, mousedown, or the JavaScript hub.

💡 Best Practices

✅ Do

  • Pair mouseenter / mouseleave for whole-component hover
  • Clean up classes, tips, and timers inside mouseleave
  • Prefer CSS :hover when you only need visual changes
  • Provide a non-hover path for touch / keyboard users
  • Prefer addEventListener in production code

❌ Don’t

  • Expect mouseleave to bubble like mouseout
  • Assume leave fires when you remove the element from the DOM
  • Leave hover UI stuck because you only handled enter
  • Assume hover UX works the same on phones
  • Overwrite onmouseleave if you need multiple listeners

Key Takeaways

Knowledge Unlocked

Five things to remember about mouseleave

Pointer left—non-bubbling hover exit.

5
Core concepts
📄02

No bubble

unlike mouseout

API
👆03

Stable exit

kids do not re-fire

Why
🔄04

mouseenter

enter pair

Pair
🎯05

Baseline

widely available

Status

❓ Frequently Asked Questions

It fires when a pointing device moves out of an element and all of its descendants. Combined with mouseenter, it behaves a lot like leaving CSS :hover for that element.
No. MDN marks Element mouseleave as Baseline Widely available (since July 2015). It is not Deprecated, Experimental, or Non-standard.
A MouseEvent (inherits from UIEvent and Event). Useful fields include clientX, clientY, relatedTarget, and modifier keys.
mouseleave does not bubble and fires only when the pointer has left the element and all descendants. mouseout bubbles and also fires when moving from the element to a descendant (or between descendants via bubbling).
It follows the element’s position in the DOM tree. Moving into a visually nested sibling can still fire mouseleave on the outer element even if the pointer stays inside the outer element’s painted box.
No. MDN notes that mouseleave and mouseout are not triggered when the element is replaced or removed from the DOM.
Did you know?

If you remove or replace an element while the pointer is over it, mouseleave will not fire. Clean up hover state yourself when you tear down DOM nodes.

Next: mousemove

Learn the high-rate event that tracks pointer motion.

mousemove →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful