jQuery Events: MouseOver / MouseOut vs. MouseEnter / MouseLeave
For years, Javascript developers have had the MouseOver and MouseOut events for triggering events when a user mouses over and out of a given HTML element. For anyone who's tried to use these, you know that they are great, but that they come with a huge problem: the mouseover and mouseout events fire for a given element if the user mouses over or out of an element nested within the given element. To get around this behavior, we've had to resort to all short of shenanigans, including the use of Javascript timers to delay "out"-based actions (assuming an "over" action might subsequently cancel a timer).
jQuery removes this headache by introducing the custom events, MouseEnter and MouseLeave. These custom events build on top of the existing mouseover and mouseout events; they travel up the DOM with each mouseover / mouseout event triggering to see if the user has truly "entered" or "left" the given element. Now these events have been in jQuery for some time; but, I've really start to leverage them a lot lately and, let me say, they make life super easier!
<!DOCTYPE HTML>
<html>
<head>
<title>MouseOver / MouseOut vs. MouseEnter / MouseLeave</title>
<style type="text/css">
#outer-mouseover {
background-color: #F0F0F0 ;
border: 1px solid #D0D0D0 ;
float: left ;
height: 225px ;
margin-right: 20px ;
position: relative ;
width: 225px ;
}
#outer-mouseenter {
background-color: #F0F0F0 ;
border: 1px solid #D0D0D0 ;
float: left ;
height: 225px ;
position: relative ;
width: 225px ;
}
span.inner {
background-color: #B3C9DF ;
border: 1px solid #6492BF ;
color: #FFFFFF ;
height: 100px ;
left: 62px ;
line-height: 98px ;
position: absolute ;
text-align: center ;
top: 62px ;
width: 100px ;
}
</style>
<script type="text/javascript" src="jquery-1.4a2.js"></script>
<script type="text/javascript">
// When the DOM is ready, init scripts.
jQuery(function( $ ){
// Bind the mouse over /out to the first DIV.
$( "#outer-mouseover" ).bind(
"mouseover mouseout",
function( event ){
console.log( event.type, " :: ", this.id );
}
);
// Bind the mouse enter to the second DIV.
$( "#outer-mouseenter" ).bind(
"mouseenter mouseleave",
function( event ){
console.log( event.type, " :: ", this.id );
}
);
});
</script>
</head>
<body>
<h1>
MouseOver / MouseOut vs. MouseEnter / MouseLeave
</h1>
<div id="outer-mouseover">
<span class="inner">MouseOver</span>
</div>
<div id="outer-mouseenter">
<span class="inner">MouseEnter</span>
</div>
</body>
</html>
If you watch the video above, you'll see that the mouseenter and mouseleave events stay more in alignment with the "intent" of the code, rather than the technical underpinnings.
jQuery takes these custom events and makes them even easier to use by wrapping them up in the convenience method, hover(). The hover() method takes two Function arguments and binds the first one as your mouseenter event handler and the second one as your mouseleave event handler:
<!DOCTYPE HTML>
<html>
<head>
<title>jQuery Hover Method</title>
<style type="text/css">
#outer-hover {
background-color: #F0F0F0 ;
border: 1px solid #D0D0D0 ;
height: 225px ;
margin-right: 20px ;
position: relative ;
width: 225px ;
}
span.inner {
background-color: #B3C9DF ;
border: 1px solid #6492BF ;
color: #FFFFFF ;
height: 100px ;
left: 62px ;
line-height: 98px ;
position: absolute ;
text-align: center ;
top: 62px ;
width: 100px ;
}
</style>
<script type="text/javascript" src="jquery-1.4a2.js"></script>
<script type="text/javascript">
// When the DOM is ready, init scripts.
jQuery(function( $ ){
// Bind the mouse enter and mouse leave events using
// the convenience method, hover().
$( "#outer-hover" ).hover(
function(){
console.log( "mouseEnter" );
},
function(){
console.log( "mouseLeave" );
}
);
});
</script>
</head>
<body>
<h1>
jQuery Hover Method
</h1>
<div id="outer-hover">
<span class="inner">Hover</span>
</div>
</body>
</html>
As you can see, jQuery's hover() method simply wraps around the mouseenter() and mouseleave() event bindings.
Like I said above, these features have been part of jQuery for a while. But, I have recently started to take full advantage of them and they have just been amazing. It's definitely a small feature that makes a big impact on the way you code your interactions.
Want to use code from this post? Check out the license.
Reader Comments
Ben,
Thanks for posting this...I am right in the middle of trying to solve this problem and this works awesomely.
The only difference is I am using ExtJS 3 and it works just the same. As an aside I'm finding a lot of similarities between ExtJS and jQuery.
As always, good info Ben! I've always been curious about the differences in those events as initially they sound so similar.
@Sam,
I've heard great things about ExtJS, especially when building real "applicationy" applications. But that aside, Hover() has been great for me recently.
@Ryan,
Heck yeah my man, glad to help clarify. For the longest time, I had no idea what the difference was. I think has become more useful recently, only because I finally get it.
Nice quick demonstration.
I need exactly the same funcionality you demonstrated here but I should bind the events to future elements as well. Unfortunately jQuery's "live" currently (1.3.2) does not support mouseenter and mouseleave. Hope they will fix it in the next version.
Ben, What is this source reference: src="jquery-1.4a2.js" ?
What version of jQuery is that?
Just for clarification, in jQuery 1.4, the $.hover() event can take one function as an argument, as well as two. This is would allow you to pass in a single function that uses $.toggleX() or something similar.
It would be the technical equivalent of actually using the events (in a single bind) that you talk about:
$(...).bind('mouseenter mouseleave', function(){
$(this).toggleClass('yay');
});
@Zoltan,
Hmm, good question. I can easily see something like this being used for dynamically added elements. It might be easier than we think; I'll put my thinking cap on.
@Kristopher,
It was an Alpha version of jQuery 1.4. Incidentally, version 1.4 was just released publicly.
@Alex,
Very interesting. I could see that being useful. When I was looking at the jQuery code, I did see that it did this:
.mouseout( fnOut || fnOver )
... but I had no idea why it was doing that. I guess that makes perfect sense in terms of toggling.
Thank you for the article. It's well made and very heplfull:)
@Luke,
Glad you got some value out of it.
Thanks for posting this, it clarifies a lot!
I thought I'd extend this a bit further, but that does not seem to work. I have two div panels, and when hovering over the first, i am showing the second.
I hoped to do this using the hover() method:
$('#id1).add('#id2).hover(....
The code above triggers a leave and enter event, even when the two div (id1 and id2) are overlapping. Any ideas how to do this?
@Pieter,
That's a very interesting situation - having two overlapping Divs with "hover" behavior. My guess is that you're gonna have trouble with that. I am not sure it's gonna be possible. You'd really have to look at the internals of the "mouseenter" / "mouseleave" events to see how they work, mechanically. If one prevents propagation of an event, I think you're gonna be out of luck.
@Pieter,
We get that question a lot in the #jquery irc channel, and I think the code you wrote works exactly as it should, however not to your specifications.
Essentially what's happening: The hover functions that you pass into the event get applied to each matching element _individually_. So the fact that they overlap should have no bearing on their events being grouped together.
I built this example for someone on IRC a few months back and it's based on a popular technique called HoverIntent that uses timeouts to see if you move to a related object:
http://jsbin.com/ulili
http://jsbin.com/ulili/edit
The functionality I think you want should be happening when you stay hovered over either the button or the rollout div.
@Alex and @Ben, thanks. It needs further testing, but it looks like it works now. Instead of using the mouseleave() event of one of the overlapping div's, I now use a mouseenter() event of the main page content to clean up the div panels.
Thanks, Ben! :) This is another outstanding example of an easy to follow yet complete technical blog post. This article helped me a lot because I had been wasting a lot of time trying to create a tooltip with a dialog when I read your post, <slapped my forehead>, I should have just used the jQuery .hover event. I had all of my MVC view's hover dialog boxes tested and working in under an hour.
@Amy,
Thanks a lot! You have no idea what kind of warm fuzzies it gives me to know that my writing is both useful and easy to understand. It is very appreciated.
@Ben,
You are very welcome. :) I've been doing a LOT with ASP.NET MVC and jQuery lately, so please feel free to let me know if you have questions I can help you with too.
@Amy,
Will do, thank you kindly for the offer.
Any idea why this animates properly then - with no extra mouse movement - jumps back to the starting position a moment later? Does the same on mouseout to0.
$('#banner').hover(function(){
$(this).animate({backgroundPosition:"-250px 0"});
$(this).animate({backgroundPosition:"0 0"});
});
I've read of problems with hover firing off for no reason. I can't stop it.
Ideas?
@Ziggy,
I am not sure I understand your issue. From your two animate calls, it looks like that is exactly what it is supposed to do - animate one way and then snap back. What are you intending it to do?
No, it is snapping back without any further mouse movement, while still hovering - it should animate (not snap) back only when the mouse no longer hovers over the div.
Hover doesn't seem to work right, or not intuitively right anyway. Are you sure hover is using MouseEnter/MouseLeave? I think it must be using mouseover and mouseout.
I changed it to use .mouseenter ... .mouseleave and it works correctly now: mouseover and it animates one way and stays there until you mouseout then it animates back.
I also added px to the zeros, I think it fixed some jumping, forget now.
Thanks. Hope it helps.
@Matt,
If you look under the hood, hover() just turns around and binds the mouseenter/mouseleave events. It's really just a convenient shorthand.
In your example above, it looks like you're using the shorter short-hand where you pass in one function and use it for BOTH the mouseenter and mouseleave events.
Is it possible that you made a typo passing in only a single function? Right now, you have *both* animate methods in a single event handler; did you mean to put on in the "enter" and one in the "leave" event handler?
Ok, I see now it is supposed to be a comma in between not a semi-colon. Uhh, jquery and untold brackets and semi-colons and commas... Thanks!
Btw, my 2 comments above now say "Matt" made them. Something messed up there.
Oh, weird, now the first 2 posts changed back to my name again.
I'm new to using jQuery, but wanted to find out if the mouseEnter and mouseLeave functions could be used to replicate the "Get Social" icon behavior located in the top right of the following website: http://www.babyphat.com.
I was initially going to use Flash but have been reading that jQuery can perform some animations without being code intensive.
Any help or suggestions would be greatly appreciated.
Thanks!
@Ziggy,
Yeah, there's some funky code behind the comment tracking because it integrates with "member" tracking on the points and comment count. It's a bit buggy from time to time.
@Kara,
There's not much that you can do in Flash that you can't do in jQuery. I don't have any specific suggestions other to say that the mouseEnter / mouseLeave can be used to create that kind of social stuff. After all, it's not much different than a drop-down menu except for that it's "dropping" left, not down.
Hi, this works great except I made the function fadeIn and fadeOut a div using the .hover. But when I hover in and out repetitively the div starts to blink even when I am not hovering over it. Is there a way to set a timer or something to stop it from doing this?
@Snowden,
This is probably happening because the events are getting queued as you enter/exit the target area. Try calling stop() before you execute the animation. This will stop any existing animation before starting the new one.
$( target ).stop().fadeOut()
its good method.. i did it with my code..(hint box)
$('.lp_pic_bg').hover(
function(){
var fav = $(this).offset().top;
$(".sand_block").show();
$(".sand_block").offset({ top: fav +50});
},
function(){
$(".sand_block").hide();
}
);
@Alex,
Alex, thank you so much for putting your code up there http://jsbin.com/ulili
This was exactly what I was looking for.
I have created a megamenu effect for Joomla site and using two separate divs is the only way to create megamenus in Joomla at the moment and your coding helps create the effect just great.
And Ben, thanks for creating such a great website with your tutorials. A real help for designers like me trying to cope with programing :)
Best wishes,
Neil.
@Neil,
I'm always happy to help; and, I'm always super thrilled when people jump in and help each other - makes me really feel like we have a good community going on here. I hope to have you back in the future.
What an incredibly clear explanation, although some of the vocabulary is new to me.
Do you have a tutorial on how to make menu items work a bit like radio buttons: when one item is clicked, it changes to and all the other menu items change to , even after mouseOut?
Thanks for putting so much time and effort into your blog.
@Ren,
I am not sure I understand what you mean. Are you talking about a Menu? Or something more like a Nav Bar? I only ask because menus typically only show while they are being used and then disappear after that.
I have a numbered menu bar/navbar(?) that changes the image on the screen, like a slide show.
The number 4, for instance, should stay in bold while the fourth image is showing.
I figured out a code that works:
<script>
$(".blur").click(function () {
$(".blur").removeClass("selected");
$(this).addClass("selected");
});
</script>
All the menu numbers start in class .blur; when clicked on, they add class .selected, which puts links in font-weight 400. Every other element in .blue loses the class .selected and reverts to normal.
Thanks for responding.
Ben
Thanks a million for this. I was trying to do this using all sorts of weird and wonderful approaches and then came across your simple example.
Love your articles.
Thanks so much.
Ian (from Ireland)
I've been using this a lot recently but just found that it doesn't work when there is a select box in the popup and it is selected. i.e. when I click the select and move the mouse over an item the popup closes.
Any ideas?
@Ian,
Can't quite understand your situation. Can you post code or send a link so I can see?
Ren
Guys,
You ROCK!!!
Thanks a lot!!!
Mate ... THANK YOU!
@Alex,
My pleasure!
sorrysorry
mots Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.
mots got you are how
I am not sure I understand what you mean. Are you talking about a Menu? Or something more like a Nav Bar? I only ask because menus typically only show while they are being used and then disappear after that.
tank you !!
I am very enjoyed for this blog.
This was very helpful. Thanks!
Thank you SO much for this! I just experienced the same mouseover/mouseout problem that you mentioned in your video and your solution worked brilliantly!! You, and JQuery, have saved me hours of time.
clear example, very useful, thanks !
Hi,
How can we highlight (just give red border) on every element on an html when mouse enter and remove border when mouse out/leave? no specific type is required. I am trying but it is selecting html tag only and do not work on inner tags/elements.
It is very easy just check the code below:
<script>
/////////////////////////////// MOUSE ENTER / LEAVE ///////////////////////////////
$(document).ready(function () {
$('body *').live('mouseover mouseout', function (event) {
if (event.type == 'mouseover') {
if (!($(this).hasClass('.highlighted'))) {
$(this).toggleClass('dotted');
}
}
else {
if (!($(this).hasClass('.highlighted'))) {
$(this).toggleClass('dotted');
}
}
return false;
});
});
/////////////////////////////// MOUSE CLICK ///////////////////////////////
$(document).ready(function () {
$('body').click(function (event) {
var $var = $(event.target);
$var.find('.highlighted').toggleClass('highlighted'); //remove any nested already selected element
$(event.target).parents('.highlighted').each(function () {
$(this).toggleClass('highlighted');
});
$(event.target).toggleClass('highlighted');
});
});
///////////////////////////////
</script>
<style type="text/css">
.highlighted
{
border: red 1px solid;
}
.dotted
{
border: blue 1px dotted;
}
</style>
I love the way you explained the difference so clearly and with a simple and very understandable example :)
Thank you so much
.hover() is awesome thanks for sharing such a wonderful article
I like it!
But I would like to use it to open a modal window (which is calling an iframe actually), and close the modal on the mouseleave event.
$( "#outer-hover" ).hover(
function(){
console.log( "mouseEnter" );
showDialog();
},
function(){
console.log( "mouseLeave" );
closeDialog();
}
);
The showDialog() function executes fine but I can't get it to close when i move the mouse out .
Any Idea why ?
How do I achieve the hiding of div if the divID is the same? sddmtag is the div name I use to hold multiple products. So when I have the following code, it works great on the FIRST instance of the div, but nowhere else on the page.
jQuery(function( $ ){
// Bind the mouse enter and mouse leave events using
// the convenience method, hover().
$("#sddmtag").hover(
function(){
alert( "mouseEnter" );
},
function(){
alert( 'hiding' );
divitem.style.visibility = 'hidden';
}
);
});
davida,
I have a similar situation, where multiple Divs are generated by repeating a control class in a loop in ASPX. The issue is you should not repeat the ID multiple times on the page.
You can try solving your problem by changing the name of each DIV, for example by adding a counter in the loop and adding the counter to the name.
Then you either add invidiual Javascript of each div:
chkQuestion.Attributes.Add("onclick", "showsub( this.questionNr.ToString () + ")");
and:
function showsub( id) {
tag = '#sddmtag' +id.toString()
$(tag).hover( ...
The simpler solution (if applicable) would bind the hover event to the class of the divs, rather than the ID.
Pieter,
This is getting my mind going in the right direction. I think I understand the approach of both possible solutions you are suggesting. Now I just need to see if I can actually put them into code! haha. I have been coding on and off for years, so I am somewhat rusty and 'average' in different languages.
I am fairly new to jquery, but have had good success in some cases. However I am not sure how to bind the hover event to a class. Any chance of posting an example of this? I just stumbled onto this article on how to use the hover event and loved it but just this one snag I have run into. My divs are products. I could name each div uniquely, no problem, but not sure how to get the .hover event to execute for each one then.
Here is my current code below. I know there is probably a REALLY simple thing I can do to the code below to get it to work, but I am not the most experienced in js or jquery yet but appreciate its power.
THE CODE I AM USING:
////////////////////////////////////////
function hidethisdiv(d) {
divloc = 'tags_sub' + d;
<!---I pass a product sku (d) which uniquely names my INNER nested div that I am showing and hiding using hover event on the OUTER container div;--->
divitem = document.getElementById(divloc);
}
jQuery(function( $ ){
<!--- Now I tell it that when the OUTER div (sddmtag) is called by .hover event, to hide or show my INNER div (referenced above as divitem). --->
$("#sddmtag").hover(
function(){
alert( "mouseEnter" );
},
function(){
alert( 'hiding' );
divitem.style.visibility = 'hidden';
}
);
});
////////////////////////////////////////
Thanks for any suggestions!
david
I found this page while reading "jQuery Compressed" on my Kindle.
Thanks Ben, You have nice smile
great article, using this to change classes on mouse event for a WP theme.
Awesome post, Thanks for sharing. Saved me a load of code and additional searching!
@Ben - Dude you just saved me a few hours an a huge headache... Thanks!
@Al,
Welcome dear !
Thanks for this post; I like this navbar.
However, it does not work for tablets, not supporting the "mouseleave":
The sub-menus appear when the menu is selected; but the slideUp is never done.
Any idea to improve it or use a workarround? know how-to have the slideUp when selecting a menu or submenu?
Thanks
Just the refresher I needed to get the job done right. Nice and easy.
This is a nice tutorial. Really helpful. Thanks
Thanks!! :D
Thanks for this article.
This just end my 15+ hour debugging session with flickering flyout menus in IE8. Old Code was using the MouseOver and MouseOut events. Somehow, it wouldn't work with newer code. Changed the events to Hover and it worked perfectly.
https://www.blogger.com/blogger.g?blogID=5520639523558571093#editor/target=post;postID=2115005821608125066
please check the link.
here the footer robo image effects how to do this work.
please help me
So glad I found this detailed description between the differences of the various mouse events we get from jQuery. I was coding an ajax action on one of my websites where I was using mouseover / mouseout. Basically, what I have works as follows:
1. User hovers over a featured image corresponding to a Wordpress post.
2. jQuery sends an ajax request to get the content of such post.
3. Content appears below the featured image on a page designated to show all posts of a custom post type.
Now the problem with the mouseover method is that the post content would appear over and over again. Think of something like a foreach loop that gets executed as many times as the mouse moves over a targeted element. The end result is a HUGE page that could very well crash a browser.
The mouseenter / mouseleave was the answer to stop the ajax request being sent over and over again. Go to http://www.cdemarco.net/skyrim/featured-modders and hover over any one of the images.
Thanks again Ben, this is much appreciated.
Just what I needed. Flickering was driving me nuts. Out of curiousity, what would be a case for using mouseover/out instead of mouseenter/leave?
@James,
Hmm, one such use case seems to be going on right at this website. In the header section of this website, we have Ben's photo, navigation, etc. Well, if you hover anywhere to the right or left of this area we see images that are otherwise hidden. Hovering over an image makes it fade in, while de-hovering makes it fade out.
@Ryan,
hello sir