Different behavior of blur event in different browsers

John Bupit picture John Bupit · Jul 8, 2014 · Viewed 7.6k times · Source

Consider this example where I have 2 input fields:

<input id="a" />
<input id="b" style="display: none" />

And consider the following JavaScript, which is an attempt to do this:

Show #b only when #a has focus and hide #b whenever #a loses focus, except when #a loses its focus to #b.

$("#a").focus(function() {
    $("#b").show();
});

$("#a, #b").blur(function() {
    $("#b").hide();
});

$("#b").focus(function(){
    $("#b").show();
});

The above code is incorrect as $("#b").focus() would never be triggered because as soon as #a loses focus, #b is hidden. This expected behavior is observed in Firefox (Version 24.6.0).

But in Chrome (Version 35.0), the code seems to run incorrectly (or correctly!?).

Clearly, the b.focus event is still being registered in Chrome. Why does this event register in Chrome, but not in Firefox?


Update

As pointed out by raina77ow:

  • In Chrome, after we place the cursor on b, blur on a is fired first, then focus on b, and b stays visible.
  • In Firefox, focus on b is not fired, so b becomes invisible.
  • In IE10, however, somehow focus on b IS fired, but b becomes invisible immediately, as blur is fired on b right after.

Here's a fiddle without using jQuery, producing the same behavior.

Answer

Nateowami picture Nateowami · Jul 11, 2014

As you know, the issue is that different browsers choose to call event handlers in different orders. One solution is to give the other events a chance to fire by setting a timer for 0 milliseconds, and then checking the fields to see which (if any) is focused.

a.onfocus = function() {show(b);};

a.onblur = function() {
    setTimeout(function() {
        //if neither filed is focused
        if(document.activeElement !== b && document.activeElement !== a){
            hide(b);
        }
            }, 0);
};

//same action as for a
b.onblur = a.onblur;

Tested in Chrome, Firefox, Internet Explorer, and Safari. See full working example (edited version of your fiddle) at JSFiddle.net.