The .hover() method is jQuery’s convenience API for binding mouseenter and mouseleave handlers in one call. This tutorial covers .hover(handlerIn, handlerOut) since 1.0, single-function .hover(handlerInOut) since 1.4, migration to .on("mouseenter") and .on("mouseleave"), and why the method is deprecated since jQuery 3.3.
01
handlerIn
Pointer enters
02
handlerOut
Pointer leaves
03
One fn
Since 1.4
04
.on()
Modern bind
05
.off()
Unbind
06
Deprecated
Since 3.3
Fundamentals
Introduction
Hover effects are everywhere on the web — menus that drop down when you point at them, buttons that change color, table rows that highlight. jQuery’s .hover() method made this easy: pass one function for when the mouse enters and another for when it leaves, without writing two separate .on() calls.
Under the hood, .hover() is not a separate browser event — it binds mouseenter and mouseleave. Those events behave differently from mouseover and mouseout: they do not re-fire when the pointer moves over child elements inside the bound node. That makes .hover() ideal for stable enter/leave behavior on containers with nested content.
Concept
Understanding the .hover() Method
The official jQuery API describes .hover() as a way to bind one or two handlers executed when the mouse pointer enters and leaves matched elements. With two functions, the first runs on enter and the second on leave. With one function (since 1.4), the same callback runs for both — inspect event.type to distinguish "mouseenter" from "mouseleave".
Calling $(selector).hover(handlerIn, handlerOut) is shorthand for:
Do not use .hover() in new code. Replace two-handler form with .on("mouseenter", fnIn).on("mouseleave", fnOut) and single-handler form with .on("mouseenter mouseleave", fn). Legacy code still runs in jQuery 3.x — migrate when you touch those files.
Foundation
📝 Syntax
The .hover() method has two signatures from the official jQuery API. Both are deprecated since 3.3:
📋 .hover() vs mouseenter / mouseleave vs mouseover
Four related concepts — know what .hover() wraps and when to prefer mouseenter over mouseover.
.hover()
deprecated
Shorthand for mouseenter + mouseleave in one call — migrate to .on()
mouseenter
enter
Fires once when pointer enters element — no re-fire on child crossing
mouseleave
leave
Fires once when pointer exits element entirely
mouseover
bubbles
Re-fires on every child boundary — use mouseenter for stable hover
Hands-On
Examples Gallery
Examples 1–4 follow the official jQuery API documentation. Example 5 covers migration to .on(). Move your pointer over the demo areas in each Try-it lab. Remember: .hover() is deprecated — these demos show legacy syntax you will encounter in older code.
📚 Two-Handler Pattern
Official jQuery demos with separate enter and leave callbacks.
Example 1 — Official Demo: Append Markers on List Hover
Add a red *** marker when the pointer enters a list item; remove it on leave. Items with class fade also pulse with fadeOut / fadeIn.
jQuery
$( "li" ).hover(
function() {
$( this ).append( $( "<span> ***</span>" ) );
},
function() {
$( this ).find( "span" ).last().remove();
}
);
$( "li.fade" ).hover( function() {
$( this ).fadeOut( 100 );
$( this ).fadeIn( 500 );
} );
Hover Milk → appends red ***
Leave → span removed
Hover Chips (has .fade) → fadeOut then fadeIn animation
How It Works
The two-function .hover(fnIn, fnOut) form runs the first callback on mouseenter and the second on mouseleave. A second .hover(singleFn) on li.fade stacks an additional enter-only animation — the single-function form runs the same handler for both events, but here only the enter animation is noticeable.
Example 2 — Official Demo: Highlight Table Cells on Hover
Add a hover class when the pointer enters a cell; remove it on leave.
jQuery
$( "td" ).hover(
function() {
$( this ).addClass( "hover" );
},
function() {
$( this ).removeClass( "hover" );
}
);
This is the most common .hover() pattern in legacy code: toggle a CSS class on enter and remove it on leave. The modern equivalent uses .on("mouseenter") and .on("mouseleave") with the same callbacks.
Example 3 — Official Demo: Unbind with .off()
Remove hover behavior from table cells — there is no "hover" event to unbind.
After .off("mouseenter mouseleave") → cells no longer highlight on hover
Click "Remove hover" button in demo to unbind handlers
How It Works
.hover() registers handlers as mouseenter and mouseleave — not under a fictional "hover" event name. Pass both event strings to .off() to remove all enter/leave handlers from the matched cells.
📈 Single Handler & Migration
One-function hover and modern .on() replacement.
Example 4 — Official Demo: Single Handler Toggles Next Sibling
One function handles both enter and leave — toggle active class and slide the next li (official 1.4 demo pattern).
Hover even li (Milk, Carrots) → .active class + next odd li slides open
Hover again (leave) → toggles back — same fn runs on enter and leave
.odd() detail rows start hidden
How It Works
When you pass one function to .hover(), jQuery binds it to both mouseenter and mouseleave. Using .toggleClass() and .slideToggle() inside means the same action reverses on leave — a compact pattern for accordion-style hover menus.
Example 5 — Migration: .hover(fnIn, fnOut) vs .on("mouseenter") / .on("mouseleave")
Both bind the same enter/leave behavior — .on() is the recommended API for new code.
jQuery
$( "#legacy" ).hover(
function() {
$( "#out" ).text( "Legacy: .hover(fnIn, fnOut) — deprecated since jQuery 3.3." );
},
function() {
$( "#out" ).text( "Legacy: pointer left #legacy." );
}
);
$( "#modern" ).on( "mouseenter", function() {
$( "#out" ).text( "Modern: .on('mouseenter') — use this for new code." );
} ).on( "mouseleave", function() {
$( "#out" ).text( "Modern: .on('mouseleave') — pointer left #modern." );
} );
Hover #legacy → legacy enter message
Leave #legacy → legacy leave message
Hover #modern → modern enter message
Leave #modern → modern leave message
Behavior is identical — only the API differs
How It Works
Under the hood, .hover(fnIn, fnOut) is exactly .on("mouseenter", fnIn).on("mouseleave", fnOut). Migration is a straight rename with no behavior change. Chaining two .on() calls keeps the same readability as one .hover() call.
Applications
🚀 Common Use Cases
Navigation menus — show dropdown on enter, hide on leave — classic .hover(fnIn, fnOut) pattern.
Table row highlight — add/remove a CSS class on td or tr hover for spreadsheet UIs.
Tooltip preview — append or show a tooltip element on enter, remove on leave.
Image swap — change src on enter, restore on leave for product galleries.
Accordion details — single-function .hover(fn) with .slideToggle() on adjacent rows.
Reading legacy code — recognize .hover() as mouseenter + mouseleave when maintaining older jQuery projects.
🧠 How .hover() Routes Through jQuery
1
You call .hover()
One function → bind to both mouseenter and mouseleave. Two functions → first is enter, second is leave.
dispatch
2
mouseenter fires
Pointer enters the element boundary — handlerIn (or handlerInOut with event.type === "mouseenter") runs.
enter
3
mouseleave fires
Pointer exits the element entirely — handlerOut runs. Moving over children does not re-trigger enter.
leave
4
👉
jQuery object returned
Chain further methods — .hover(fnIn, fnOut).addClass("ready") works like separate .on() calls.
Important
📝 Notes
Deprecated since jQuery 3.3 — use .on("mouseenter", fnIn).on("mouseleave", fnOut) in new code.
Two-handler form since jQuery 1.0; single-handler form since 1.4.
There is no "hover" event — unbind with .off("mouseenter mouseleave").
mouseenter / mouseleave do not bubble from children — stable for containers with nested elements.
Prefer CSS :hover for pure styling; use JavaScript hover handlers for DOM changes and animations.
Touch devices have no true hover — provide click/tap alternatives for mobile users.
Do not confuse .hover() with the removed .live() or browser mouseover — each behaves differently.
Compatibility
Browser Support
The underlying mouseenter and mouseleave events are supported in every browser jQuery targets. The .hover() method itself is a jQuery API — it works in jQuery 1.x, 2.x, and 3.x. Binding via .hover() is deprecated since 3.3 but still functional.
✓ jQuery 1.0+
jQuery .hover() method
Supported across all jQuery versions you are likely to maintain. Deprecated since 3.3 — use .on('mouseenter') and .on('mouseleave') for new projects. Native equivalents: element.addEventListener('mouseenter', fn) and addEventListener('mouseleave', fn).
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
.hover()Legacy API
Bottom line: Safe in legacy jQuery projects. Migrate to .on('mouseenter') / .on('mouseleave') when updating code. Test touch devices separately — hover has no mobile equivalent.
Wrap Up
Conclusion
The jQuery .hover() method is the legacy shorthand for binding mouseenter and mouseleave handlers. Use .hover(handlerIn, handlerOut) for separate enter/leave callbacks, or .hover(handlerInOut) when one function handles both — both forms deprecated since jQuery 3.3.
For new code, prefer .on("mouseenter", fnIn).on("mouseleave", fnOut) or .on("mouseenter mouseleave", fn). Unbind with .off("mouseenter mouseleave"). When you encounter .hover() in older projects, recognize it, understand it, and migrate when practical.
Use .on("mouseenter", fnIn).on("mouseleave", fnOut) for new hover bindings
Prefer CSS :hover when only colors or visibility change
Use mouseenter / mouseleave instead of mouseover / mouseout for stable hover
Call .off("mouseenter mouseleave") when removing hover behavior
Provide tap/click fallbacks for touch devices
❌ Don’t
Write new code with deprecated .hover()
Try to unbind with .off("hover") — that event name does not exist
Use mouseover when you mean enter-once behavior — it re-fires on children
Rely on hover alone for critical UI on mobile
Stack many .hover() calls without understanding handler order
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about .hover()
Enter, leave, migrate.
6
Core concepts
in/out01
.hover(in,out)
Two fns
Deprecated
fn02
.hover(fn)
Since 1.4
Single
enter03
mouseenter
Under hood
Event
leave04
mouseleave
Under hood
Event
.on05
.on()
Modern
Replace
3.306
Deprecated
Since 3.3
Migrate
❓ Frequently Asked Questions
The .hover() method binds handlers for mouseenter and mouseleave in one call. With two functions — .hover(handlerIn, handlerOut) — handlerIn runs when the pointer enters the element and handlerOut when it leaves. With one function since jQuery 1.4 — .hover(handlerInOut) — the same function runs for both events; check event.type inside. Deprecated since 3.3.
Yes — both .hover(handlerIn, handlerOut) and .hover(handlerInOut) are deprecated since jQuery 3.3. Use .on('mouseenter', handlerIn).on('mouseleave', handlerOut) for two handlers, or .on('mouseenter mouseleave', handlerInOut) for one. Existing legacy code still runs in jQuery 3.x; migrate when you refactor those files.
CSS :hover is a stylesheet pseudo-class — no JavaScript required for simple color or visibility changes. jQuery .hover() runs JavaScript callbacks on mouseenter and mouseleave — useful for DOM changes, animations, and logic CSS cannot express. For pure styling, prefer CSS; for behavior, use .on('mouseenter') and .on('mouseleave') in modern code.
.hover() is shorthand for mouseenter + mouseleave. mouseenter fires when the pointer enters an element and does not re-fire when moving over child elements inside it. mouseover bubbles and re-fires on every child boundary crossing. For typical hover menus and highlights, mouseenter/mouseleave (via .hover() or .on()) are the right choice.
Use .off('mouseenter mouseleave') on the same selector — .hover() registers under those event names, not a separate 'hover' event. Example: $('td').off('mouseenter mouseleave') removes handlers bound by the official table-cell hover demo.
Replace .hover(fnIn, fnOut) with .on('mouseenter', fnIn).on('mouseleave', fnOut). Replace .hover(fn) with .on('mouseenter mouseleave', fn). Under the hood, .hover() already delegates to those events — migration is a straight rename with no behavior change for simple bindings.
Did you know?
jQuery’s .hover() never introduced a browser "hover" event — it always mapped to mouseenter and mouseleave. That is why unbinding requires .off("mouseenter mouseleave"), as documented in the official API Example 3. The method was deprecated in 3.3 alongside other event shorthands like .click(handler), steering developers toward the unified .on() API from jQuery 1.7.