The mousemove event fires whenever the pointer moves inside an element. This tutorial covers binding with .on("mousemove"), reading coordinates with event.pageX and event.pageY, triggering with .trigger("mousemove"), performance tips for high-frequency handlers, and the drag pattern that binds on mousedown and unbinds on mouseup.
01
.on()
Bind handler
02
pageX/Y
Coordinates
03
.trigger()
Fire mousemove
04
Performance
High frequency
05
Drag pattern
Bind & unbind
06
Since 1.7
Modern API
Fundamentals
Introduction
Most mouse events fire once per user action — a click, a press, an enter. mousemove is different: it fires continuously while the pointer moves inside an element, sometimes hundreds of times per second. That makes it essential for drag-and-drop, drawing tools, custom sliders, live coordinate displays, and any UI that must follow the cursor.
The official jQuery API distinguishes the mousemoveevent (bound with .on("mousemove") since 1.7) from the deprecated .mousemove()method used in older code. To programmatically fire a handler, use .trigger("mousemove") — available since jQuery 1.0. Any HTML element can receive the mousemove event.
Concept
Understanding the mousemove Event
The mousemove event is sent to an element when the mouse pointer moves inside that element. jQuery normalizes coordinate properties — especially event.pageX and event.pageY — so you can read pointer position consistently across browsers.
Because the event fires on every pixel of movement, handlers must stay lightweight. The official jQuery documentation recommends binding mousemove only when needed — often from a mousedown handler — and unbinding it from a mouseup handler attached high in the DOM tree (such as document), since release may occur outside the original element.
💡
Beginner Tip
Do not leave a permanent mousemove handler on document unless you truly need global tracking. For drag operations, bind on press, track during move, and unbind on release — this keeps your page responsive.
Foundation
📝 Syntax
The modern jQuery API for the mousemove event has two main forms — binding a handler and triggering the event:
📋 mousemove vs mouseover vs mouseenter vs deprecated .mousemove()
Four related pointer events — choose the one that matches how often and when you need to respond.
mousemove
continuous
Fires on every pointer movement inside the element — high frequency
mouseover
enter+bubble
Fires when pointer enters element or child — bubbles up the tree
mouseenter
enter once
Fires once when pointer enters — no re-fire on child crossings
.mousemove() method
deprecated
Old binding shorthand — use .on("mousemove") instead
Hands-On
Examples Gallery
Examples 1–3 follow the official jQuery API documentation. Examples 4–5 cover the drag bind/unbind pattern and live coordinate tracking. Use the Try-it links to run each snippet in the browser.
📚 Binding & Triggering
Official jQuery demos for mousemove handlers and programmatic triggers.
Example 1 — Official Demo: Log Coordinates on #target
Append a message with event.pageX and event.pageY each time the pointer moves over the target — the canonical .on("mousemove") pattern.
jQuery
$( "#target" ).on( "mousemove", function( event ) {
var msg = "Handler for `mousemove` called at ";
msg += event.pageX + ", " + event.pageY;
$( "#log" ).append( "<p>" + msg + "</p>" );
} );
Move pointer over #target → log lines like:
Handler for mousemove called at (399, 48)
Handler for mousemove called at (398, 46)
Handler for mousemove called at (397, 44)
Many events fire during a small hand movement
How It Works
.on("mousemove", fn) registers the function on the element. jQuery calls it on every pointer movement inside the element boundary. event.pageX and event.pageY are normalized by jQuery for cross-browser consistency.
Example 2 — Official Demo: #other Triggers mousemove on #target
One element programmatically fires the mousemove handler on another — note the official API shows coordinates as undefined when triggered without a real pointer position.
Move over #target → coordinates logged normally
Click #other → trigger runs handler with:
Handler for mousemove called at (undefined, undefined)
Programmatic trigger has no real pointer position
How It Works
.trigger("mousemove") synthetically fires the event on #target, running bound handlers. Without a real mouse event, coordinate properties may be undefined — pass a custom event object if your handler requires specific values.
Example 3 — Official Demo: pageX/pageY vs clientX/clientY
Show both coordinate systems when the pointer moves over a yellow div — adapted from the official jQuery API demo.
Move over the yellow div:
( event.pageX, event.pageY ) : ( 120, 85 )
( event.clientX, event.clientY ) : ( 120, 85 )
Values differ when the page is scrolled — pageX includes scroll offset
How It Works
pageX/pageY measure from the document origin; clientX/clientY measure from the viewport. jQuery normalizes pageX and pageY across browsers — use them when positioning elements relative to the full page.
📈 Performance & Drag Patterns
Patterns from the official API notes — bind only during drag and unbind when done.
Example 4 — Bind on mousedown, Unbind on mouseup (Drag Pattern)
Track pointer movement only while the user is dragging — the official API’s recommended optimization for mousemove handlers.
Press left button on #box → mousemove bound to document
Drag anywhere → box follows cursor
Release anywhere → mousemove unbound, no further tracking
mouseup on document catches release outside #box
How It Works
Binding mousemove permanently would waste CPU. Instead, bind on mousedown, attach mousemove to document for global tracking, and use $(document).one("mouseup", ...) to unbind — even if the user releases outside the original element.
Example 5 — Live Coordinate Display Inside a Zone
Show real-time X/Y coordinates and a crosshair marker that follows the pointer — a practical pattern for image maps, drawing previews, and debug overlays.
jQuery
var $zone = $( "#zone" );
var $marker = $( "#marker" );
var $readout = $( "#readout" );
$zone.on( "mousemove", function( event ) {
var offset = $zone.offset();
var x = event.pageX - offset.left;
var y = event.pageY - offset.top;
$marker.css( { left: x - 6, top: y - 6 } );
$readout.text( "Local: " + Math.round( x ) + ", " + Math.round( y ) );
} );
$zone.on( "mouseleave", function() {
$readout.text( "Move pointer inside the zone" );
} );
Move inside #zone → readout shows local coordinates
Red marker follows pointer relative to zone top-left
Leave zone → readout resets via mouseleave handler
Subtract offset() from pageX/pageY for element-local coords
How It Works
event.pageX minus $zone.offset().left converts document coordinates to coordinates relative to the element’s top-left corner. Pairing with mouseleave resets the UI when the pointer exits the tracking area.
Applications
🚀 Common Use Cases
Drag-and-drop — bind mousemove on document during mousedown, unbind on mouseup.
Drawing tools — track pointer on canvas during stroke: mousedown start, mousemove draw, mouseup finish.
Custom sliders — update thumb position from event.pageX while dragging.
Image map previews — show local X/Y over a photo or diagram on mousemove.
Tooltip positioning — move a tooltip near the cursor using page coordinates.
Debug overlays — display live coordinate readouts during development.
🧠 How the mousemove Event Fits a Drag Gesture
1
Pointer over element
User moves cursor inside the target — no mousemove handler needed yet unless you want permanent tracking.
ready
2
Button pressed
User presses mouse button — mousedown fires. Bind mousemove on document to start tracking.
mousedown
3
Pointer moves
User drags — mousemove fires continuously. Read event.pageX/event.pageY and update position.
mousemove
4
👉
Button released
mouseup fires — often on document. Unbind mousemove to stop tracking and free browser resources.
Important
📝 Notes
Bind with .on("mousemove", handler) since jQuery 1.7 — not the deprecated .mousemove(handler) method.
Trigger with .trigger("mousemove") since jQuery 1.0 — coordinates may be undefined without a real pointer event.
mousemove fires on every pixel of movement — keep handlers fast and unbind when done.
jQuery normalizes event.pageX and event.pageY for cross-browser use.
Bind mouseup on document when tracking drags — release may occur outside the original element.
Any HTML element can receive mousemove — not limited to <canvas> or interactive widgets.
Use .off("mousemove") to remove handlers — avoid deprecated .unbind("mousemove").
For enter/leave hover effects without continuous tracking, prefer mouseenter and mouseleave over mousemove.
Compatibility
Browser Support
The mousemove event is a standard DOM event supported in every browser jQuery targets. jQuery’s .on("mousemove") (since 1.7) and .trigger("mousemove") (since 1.0) normalize cross-browser behavior — including event.pageX and event.pageY coordinates.
✓ jQuery 1.7+
jQuery mousemove event
Supported in jQuery 1.x, 2.x, and 3.x across all modern browsers and IE with supported jQuery versions. Native equivalent: element.addEventListener('mousemove', fn) — jQuery adds collection binding, eventData, delegation, and .trigger() in one chainable API.
100%With jQuery loaded
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
mousemoveUniversal
Bottom line: Safe in any jQuery project. Prefer .on('mousemove') over deprecated .mousemove() for binding. Optimize handlers — unbind when tracking is no longer needed.
Wrap Up
Conclusion
The jQuery mousemove event fires continuously while the pointer moves inside an element. Bind handlers with .on("mousemove", fn), read coordinates with event.pageX and event.pageY, and fire handlers programmatically with .trigger("mousemove").
Because mousemove is high-frequency, keep handlers lightweight and unbind them when tracking ends — especially in drag patterns that bind on mousedown and unbind on mouseup. For simple hover styling, use CSS or mouseenter/mouseleave instead of permanent mousemove listeners.
Bind with .on("mousemove", handler) — the modern, delegation-capable API
Use event.pageX and event.pageY for document-relative positioning
Bind mousemove only during drag — from mousedown, unbind on document mouseup
Keep handler logic minimal — defer heavy work with requestAnimationFrame if needed
Call .off("mousemove") when removing elements or tearing down handlers
❌ Don’t
Use deprecated .mousemove(handler) for new code — use .on("mousemove")
Leave permanent mousemove on document without a clear need
Perform expensive DOM reflows on every mousemove event
Bind mouseup only on the drag source — release may happen elsewhere
Assume .trigger("mousemove") includes real pointer coordinates
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about the mousemove event
Track, optimize, unbind.
6
Core concepts
.on01
.on("mousemove")
Bind
API
XY02
pageX/pageY
Coords
Position
⚡03
.trigger()
Fire
Programmatic
⚡04
High frequency
Performance
Optimize
drag05
Bind/unbind
Pattern
Drag
.off06
.off("mousemove")
Cleanup
Unbind
❓ Frequently Asked Questions
The mousemove event fires whenever the mouse pointer moves while it is inside an element — even by a single pixel. In modern jQuery, bind handlers with .on('mousemove', handler) since version 1.7. Any HTML element can receive this event. It is one of the highest-frequency browser events, so handlers should stay lightweight.
event.pageX and event.pageY give coordinates relative to the top-left corner of the entire document (including scrolled content). event.clientX and event.clientY are relative to the browser viewport (the visible window). jQuery normalizes pageX and pageY so they work consistently across browsers. Use pageX/pageY when positioning elements on the page; use clientX/clientY when you care about viewport position.
mousemove can fire hundreds of times per second during even a small hand movement. If your handler does heavy DOM updates, layout calculations, or runs multiple times per frame, it can slow the browser noticeably. Keep handlers fast, throttle or requestAnimationFrame updates when possible, and unbind mousemove as soon as you no longer need it — especially after drag operations end.
A common pattern from the official jQuery API: bind mousemove inside a mousedown handler, then unbind it from a mouseup handler. Because mouseup may fire on a different element than mousemove, attach the mouseup handler high in the DOM tree — typically $(document).on('mouseup', fn) or $(document).one('mouseup', fn).
Call .trigger('mousemove') on the target element: $('#target').trigger('mousemove'). Available since jQuery 1.0, trigger runs bound mousemove handlers. Note that programmatic triggers do not include real pointer coordinates — event.pageX and event.pageY may be undefined unless you pass them via a custom event object.
Use .on('mousemove', handler) for binding. The old .mousemove(handler) shorthand still works but is deprecated since jQuery 3.3 — it wraps .on('mousemove'). For unbinding, use .off('mousemove') instead of .unbind('mousemove'). .on() also supports event delegation: .on('mousemove', '.handle', fn).
Did you know?
The official jQuery API warns that mousemove can fire hundreds of times during a very small hand movement. If your handler does significant processing — or if multiple handlers exist for the same event — it can become a serious performance drain. That is why drag libraries bind mousemove only after mousedown and unbind it on mouseup, rather than listening globally at all times.