JavaScript Mouse Events

Mouse events fire when the user interacts with elements using a pointing device. JavaScript provides a rich set of mouse events that cover clicks, movement, hovering, and right-click context menus.

Click Events

The click event fires when the user presses and releases the primary mouse button on an element. dblclick fires on a double-click. Both receive a MouseEvent object.

click and dblclick
const box = document.getElementById("box");

box.addEventListener("click", (e) => {
  console.log("Single click at", e.clientX, e.clientY);
});

box.addEventListener("dblclick", (e) => {
  console.log("Double click at", e.clientX, e.clientY);
});

mousedown and mouseup

mousedown fires when a mouse button is pressed, and mouseup fires when it is released. Together they form a click. The button property tells you which button was used (0 = left, 1 = middle, 2 = right).

Press and Release
const box = document.getElementById("box");

box.addEventListener("mousedown", (e) => {
  console.log("Mouse down — button:", e.button);
  // 0 = left, 1 = middle, 2 = right
});

box.addEventListener("mouseup", (e) => {
  console.log("Mouse up — button:", e.button);
});

mousemove

Fires continuously as the mouse pointer moves over an element. Because it fires very frequently, heavy operations inside the handler should be throttled for performance.

Tracking Mouse Movement
const canvas = document.getElementById("canvas");

canvas.addEventListener("mousemove", (e) => {
  console.log(`Mouse at (${e.offsetX}, ${e.offsetY})`);
});

// Throttled version for better performance
let lastTime = 0;
canvas.addEventListener("mousemove", (e) => {
  const now = Date.now();
  if (now - lastTime > 100) { // fire at most every 100ms
    console.log(`Throttled: (${e.offsetX}, ${e.offsetY})`);
    lastTime = now;
  }
});

mouseenter / mouseleave vs mouseover / mouseout

These events detect when the pointer enters or leaves an element. The key difference is that mouseenter/mouseleave do NOT bubble and do NOT fire when moving between child elements, while mouseover/mouseout DO bubble and fire for child transitions.

Enter/Leave vs Over/Out
const parent = document.getElementById("parent");

// Does NOT fire when moving between children
parent.addEventListener("mouseenter", () => {
  console.log("mouseenter — entered parent");
});
parent.addEventListener("mouseleave", () => {
  console.log("mouseleave — left parent");
});

// DOES fire when moving between children (bubbles)
parent.addEventListener("mouseover", () => {
  console.log("mouseover — fires for children too");
});
parent.addEventListener("mouseout", () => {
  console.log("mouseout — fires for children too");
});
Event pairBubbles?Fires for child transitions?
mouseenter / mouseleaveNoNo — only when entering/leaving the element itself
mouseover / mouseoutYesYes — fires when moving between child elements

contextmenu (Right-Click)

The contextmenu event fires when the user right-clicks (or uses the context menu key). You can prevent the default context menu with e.preventDefault().

Custom Context Menu
const area = document.getElementById("editor");

area.addEventListener("contextmenu", (e) => {
  e.preventDefault(); // block default browser menu
  console.log("Right-click at", e.clientX, e.clientY);
  console.log("Show custom context menu here");
});

Event Coordinates

Mouse events carry several coordinate properties. Choosing the right one depends on whether you need coordinates relative to the viewport, the page, the screen, or the target element.

PropertyRelative To
clientX / clientYThe browser viewport (visible area)
pageX / pageYThe full document (includes scroll offset)
screenX / screenYThe physical monitor screen
offsetX / offsetYThe target element's padding edge
Comparing Coordinates
document.addEventListener("click", (e) => {
  console.log("clientX/Y:", e.clientX, e.clientY);  // viewport
  console.log("pageX/Y:",   e.pageX,   e.pageY);    // document
  console.log("screenX/Y:", e.screenX, e.screenY);  // monitor
  console.log("offsetX/Y:", e.offsetX, e.offsetY);  // element
});
📝 Note: Use mouseenter/mouseleave for hover effects — they are simpler and more predictable than mouseover/mouseout because they ignore child element transitions.
Exercise:
Which coordinate property gives the mouse position relative to the full document (including scrolled area)?
Try it YourselfCtrl+Enter to run
Click Run to see the output here.