Clicks
click is the event you will use most. Use it on buttons and links: browsers also fire click when a focused button is activated with Enter or Space, so keyboard users get the same behaviour for free.
<button id="one">Real button</button>
<div id="two" style="display:inline-block; padding: 4px 8px; border: 1px solid">Clickable div</div>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#one, #two").on("click", function () {
console.log("clicked", this.id);
});
</script>clicked one
clicked twoBoth respond to a mouse click, but only the real <button> can be reached with the Tab key and activated with the keyboard. If you must make a div clickable, add tabindex="0", role="button" and a keydown handler for Enter and Space. Using a <button> is far simpler.
dblclick fires on a double-click. It is rare on the web and has no keyboard equivalent, so avoid putting important actions behind it.
Entering and leaving
mouseenter fires when the pointer moves onto an element; mouseleave when it moves off:
<style>
#tile { width: 220px; padding: 16px; background: #f1f5f9; transition: background .2s; }
#tile.over { background: #fde68a; }
</style>
<div id="tile">Hover over this tile<p>It has a paragraph inside.</p></div>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#tile")
.on("mouseenter", function () { $(this).addClass("over"); console.log("enter"); })
.on("mouseleave", function () { $(this).removeClass("over"); console.log("leave"); });
</script>enterThe output shows a single enter (the example simulates the pointer arriving). Move your own mouse in and out of the tile in the editor to see leave too.
Why mouseover flickers
There is an older pair, mouseover and mouseout. The difference matters when the element has children:
mouseenter/mouseleavefire once for the element. Moving between its children does nothing.mouseover/mouseoutbubble: they fire again every time the pointer moves onto or off a child, and the parent's handler hears them.
<ul id="menu" style="padding: 8px 24px; background: #f1f5f9">
<li>Home</li>
<li>Shop</li>
</ul>
<button id="report">Report</button>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
let enters = 0, overs = 0;
$("#menu")
.on("mouseenter", () => enters++)
.on("mouseover", () => overs++);
$("#report").on("click", () => console.log("mouseenter fired", enters, "time(s); mouseover fired", overs, "time(s)"));
</script>mouseenter fired 1 time(s); mouseover fired 3 time(s)The pointer entered the menu and then moved over its two items, and the Report button printed the counts. mouseenter fired once, but mouseover fired for the menu and again for each item. If your mouseover handler toggled a dropdown, it would flicker as the user moved across the items. Use mouseenter and mouseleave for hover effects.
The .hover() shorthand
You will see .hover(overFn, outFn) in older code. It attaches the first function to mouseenter and the second to mouseleave:
$(".card").hover(
function () { $(this).addClass("raised"); },
function () { $(this).removeClass("raised"); }
);It still works in jQuery 4 but is deprecated. The modern equivalent is two .on() calls, as in the tile example.
Following the pointer
mousemove fires many times a second as the pointer moves. The event object gives the position:
<div id="pad" style="height: 120px; background: #ecfeff; border: 1px dashed #06b6d4">Move the mouse here</div>
<p id="pos">x: -, y: -</p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#pad").on("mousemove", function (event) {
const box = $(this).offset();
const x = Math.round(event.pageX - box.left);
const y = Math.round(event.pageY - box.top);
$("#pos").text("x: " + x + ", y: " + y);
});
</script>Subtracting the element's .offset() from event.pageX and pageY gives the position inside the element. Keep mousemove handlers tiny, because they run constantly.
Hover is not enough on its own
Touch screens have no hover, and keyboard users move between elements with Tab. A feature that only appears on hover, such as a dropdown menu or a delete button, is invisible to them. Pair hover with something else:
- show the same thing on
focus(or use CSS:focus-within) so keyboard users get it; - make it open on
clickas well, so touch users can tap; - or simply show the control all the time on small screens.
For purely visual effects (a shadow, a colour change), CSS :hover is simpler than jQuery and needs no JavaScript at all.
Common mistakes
- Using
mouseover/mouseoutfor hover effects on elements with children. - Making
divelements clickable instead of using buttons and links. - Hiding essential features behind hover.
- Doing heavy work in
mousemove, such as rebuilding HTML on every event.
Exercise
Make an image placeholder (a coloured div) that shows a caption when the pointer enters and hides it when the pointer leaves. Also show the caption when the div receives keyboard focus.
Show one possible answer
<div id="photo" tabindex="0" style="width: 200px; height: 100px; background: #c7d2fe"></div>
<p id="caption" hidden>Sunrise over the lake</p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#photo")
.on("mouseenter focus", () => $("#caption").prop("hidden", false))
.on("mouseleave blur", () => $("#caption").prop("hidden", true));
</script>Sunrise over the lakeKey points
- click and dblclick fire on clicks; click also fires when a focused button or link is activated with the keyboard.
- mouseenter and mouseleave fire once when the pointer enters or leaves an element, ignoring its children.
- mouseover and mouseout also fire when moving between child elements, which often causes flicker.
- Do not hide important features behind hover alone; touch screens and keyboards have no hover.