Me!

TJ VanToll

Bugs with document.activeElement in Internet Explorer

| Comments

There are two fun bugs related to document.activeElement in IE that have come up recently in jQuery UI. To help save others some pain, I felt these needed to be documented.

Accessing document.activeElement from an <iframe> in IE9

Let’s say you have an <iframe>.

<iframe src="other.html"></iframe>

And in that <iframe>, you want to know what element has focus.

/* other.html */
<script>
    console.log( parent.document.activeElement );
</script>

In all browsers except IE9, this will log the element that has focus in the parent document (the <body> by default). In IE9 this will inexplicably throw an "Unspecified Error".

Yes, you read right; ACCESSING the activeElement property of a parent document throws an error in IE9.

What can you to about it? Since the access causes the error, the only recourse is a try / catch.

var activeElement;
try {
    activeElement = parent.document.activeElement;
} catch( error ) {
    activeElement = parent.document.body;
}

Luckily this is a problem unique to IE9; the same behavior is not present in IE 7, 8, or 10.

Blurring the <body> Switches Windows in IE9 and IE10

If you call document.body.blur() in IE9 or IE10, you will switch application windows. Yes you again read right; if you have IE and Notepad open, calling document.body.blur() will switch focus to Notepad. If you don’t believe me, open IE9 or IE10 and try for yourself - run document.body.blur() in the console.

Why is this problematic?

Recall from the earlier section that the default activeElement is the <body>. Therefore, if you generically call document.activeElement.blur(), you will likely end up switching application windows for your users.

The workaround for this is to ensure the activeElement is not the <body> before calling blur().

if ( document.activeElement.nodeName.toLowerCase() !== "body" ) {
    document.activeElement.blur();
}

Luckily this problem has been fixed in IE11; document.body.blur() no longer switches windows.

Putting it all Together

This is the commit I ended up using for the jQuery UI bugs.

From:

$( document.activeElement ).blur();

To:

// support: IE9
// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
try {
    // Support: IE9+
    // If the <body> is blurred, IE will switch windows, see #9520
    if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
        // Blur any element that currently has focus, see #4261
        $( document.activeElement ).blur();
    }
} catch ( error ) {}

Sigh.

Comments