Handling browser events in JavaScript is probably the most time-consuming, frustrating, and misunderstood aspects of client-side programming. Libraries such as jQuery make it easier, but it’s still useful to have a little knowledge of what’s going on beneath the surface.
In this article, we will implement event latency, i.e. the response to an event will occur a little time after it fired. This is often useful in situations such as creating drop-down menus. So let’s start with a little HTML and CSS code (it’s kept brief for the purpose of this example, hence no DOCTYPE)…
<html>
<head>
<title>Latency test</title>
<style type="text/css">
#element1
{
width: 20em;
margin: 20px;
background-color: #dff;
border: 2px solid #00d;
}
#para1
{
text-align: center;
padding: 10px;
margin: 30px;
background-color: #ccc;
border: 1px solid #000;
}
</style>
</head>
<body>
<div id="element1">
<p id="para1">Hover over me...</p>
</div>
</body>
</html>
This just produces a box similar to the following…

Now we’ll add a little JavaScript just before the closing body tag…
<script type="text/javascript">
window.onload = function() {
// get nodes
var element1 = document.getElementById("element1");
var para1 = document.getElementById("para1");
// define events
if (element1 && para1) {
element1.onmouseover = Handler;
element1.onmouseout = Handler;
}
// event handler
function Handler(e) {
e = (e ? e : window.event);
var on = (e.type == "mouseover");
Highlight(on);
return false;
}
// highlight or dim element (pass true|false)
function Highlight(on) {
para1.firstChild.nodeValue = (on ? "over" : "out");
element1.style.backgroundColor = (on ? "#ffd" : "#dff");
if (!on) alert("moved out");
}
};
</script>
This adds a couple of (DOM0) events that fire when the cursor moves over or out of the light-blue element1 div. An event Handler function is called to sort out IE inconsistencies and discover whether a mouse over or out event was fired. The Highlight function is passed true (mouse over) or false (mouse out) and it changes the paragraph text and background color accordingly. Finally, if the mouse is moved out, an alert box is shown.
The script works, however, when we move the mouse into the grey paragraph box the “moved out” alert appears. This occurs because the browser fires two events – a mouseout for element1 and a mouseover for para1. Although we did not delegate an event handler for para1, browsers implement a technique known as bubbling and events will propagate through all element1’s descendants.
In this example, we only care if the last event fired was a mouseout that was not immediately followed by a mouseover. We can therefore fix the problem in our Handler() function with a little event latency:
var timer;
function Handler(e) {
e = (e ? e : window.event);
var on = (e.type == "mouseover");
if (timer) clearTimeout(timer);
timer = setTimeout( function() { Highlight(on); }, 300);
return false;
}
When an event occurs, we clear any existing timeout. A new timeout is then created which calls the Highlight function after 300 milliseconds (Highlight(on) is contained in a function so the value of ‘on’ is retained by the closure). This process makes it impossible for Highlight() to be executed any more frequently than every 300 milliseconds. When it is called, only the most recent value of ‘on’ is available.
Reload the page and you will notice that there is a short delay before any event animation occurs. In addition, the alert will only appear when you move outside of the blue #element1 box.
I hope you find the technique useful in other JavaScript projects.
Related posts:
- Truthy and Falsy: When All is Not Equal in JavaScript Anything in JavaScript can be considered to be either truthy...
- Fixing Object Instances in JavaScript Even experienced coders can get caught out by object handling...
- How to Write a Cookie-less Session Library for JavaScript Craig provides the code for a stand-alone JavaScript session variable...
- Techy Treasures #3: When is a mouseout not a mouseout? I've had this little gadget in my toolbox for a...
- Progressive Enhancement Techniques 3: the JavaScript This is the final of a 3-part series in which...







Good topic to cover, thanks. I recently implemented a solution like this for some dropdown menus. Users sometimes have trouble keeping the mouse pointer over the menu elements while moving it to choose one, and you don’t want the menu to collapse itself immediately when the pointer leaves for just a fraction of a second. So the menu is on a delay similar to your code that watches for the mouse returning to the menu within X milliseconds to cancel the collapse.
June 18th, 2009 at 10:21 am
There’s a couple of things wrong with this.
Firstly – the issue you mentioned of mouseout and mouseover events cross-firing between the two elements is far better fixed by discriminating the event target using a contains() method:
object.contains = function(node)
{
if(node == this) { return true; }
if(nodes == null) { return false; }
else { return this.contains(node.parentNode); }
}
Using a timer to fix this issue is really just pasting over it, and not dealing with it at all – if you rely on such a solution, I guarantee it will come back and bite you later on.
Secondly – you say that a timer is useful for dropdown menus, but it’s only useful if it’s discriminated in some way. You need to ensure that the event is still inside the target element at the end of the timer, otherwise all you’ve done is introduce a useless pause.
June 19th, 2009 at 2:26 am
Sorry, here’s that method again (free of typos this time!)
object.contains = function(node) { if(node == this) { return true; } if(node == null) { return false; } else { return this.contains(node.parentNode); } };June 19th, 2009 at 2:28 am
Thanks for the feedback. The code above was a quick example showing how event latency can be implemented with setTimeout. It’s certainly not a solution for cross-firing issues, so apologies if that’s not clear enough.
June 19th, 2009 at 5:24 am
What did you intend it as a solution for?
June 19th, 2009 at 9:21 am
I think i’ve seen this somewhere beforeā¦but it’s not bad at all
June 26th, 2009 at 4:46 am
How about doing a re-write then, using a real example?
As it stands, the article doesn’t really match the title.
June 27th, 2009 at 10:06 pm