Internet Explorer et le focus automatique sur certains éléments HTML

Parfois au boulot on croit qu'on en a finit avec IE, ses comportements erratiques, son non respect des standards… Et puis à chaque fois on retrombe dessus. Dans ce cas, il s'agit de la gestion du focus.

L'exemple étudié sera simple : un élément « cible » div sur lequel on souhaite écouter l'événement focus et qui possède 2 autres éléments div comme enfants. On indique dans le code HTML que seul le div parent doit participer au chaînage de focus grâce à l'attribut tabindex.

<div id="target" tabindex="0">
    <div>Header</div>
    <div>Body</div>
</div>
Code HTML du test.
/**
 *  Elément cible de l'écoute de focus.
 *  @type HTMLDivElement
 */
var target = document.getElementById('target');
/**
 *  Ecouteur de focus
 *  @param {Event} e DOM event
 */
var onFocus = function(e) {
    console.log(document.activeElement);
};
// Ecoute du focus sur la cible
target.addEventListener('focus', onFocus, false);
Code javascript du test.
Header
Body
Rendu du test.

Qu'obtient-on ? Si vous êtes sous Firefox ou Chrome, aucun soucis : l'élément cible prend le focus (liseret rouge pointillé) quel que soit l'endroit où vous cliquer. Par contre si vous utilisez Internet Explorer, le focus restera sur l'élément div sur lequel vous aurez cliqué (header ou body). La documentation de Microsoft indique que c'est un comportement voulu et qu'on aura la même chose avec des tableaux ou des cellules de tableau, ce qui n'est évidemment pas ce que l'on souhaite.

Que faire ? Il faut, quand on est sous IE, (1) transférer le focus sur l'élément cible grâce à l'événement focusin et (2) interdire la perte de focus de l'élément cible avec l'événement mousedown :

if (navigator.appName == 'Microsoft Internet Explorer') {
    /**
     *  Transférer le focus sur l'élément principal
     *  @param {Event} e
     */
    var onFocusIn = function(e) {
        if (e.target !== target) {
            target.focus();
        }
    };
    /**
     *  Interdire la perte de focus vers un enfant.
     *  @param {Event} e
     */
    var onMouseDown = function(e) {
        if (document.activeElement !== target) {
            e.preventDefault();
        }
    };
    // Ecoute des évenements pour gérer le transfert du focus.
    target.addEventListener('focusin', onFocuIn, false);
    target.addEventLister('mousedown', onMouseDown, false);
}
Code javascript spécifique pour Internet Explorer.
Header
Body
Rendu du test corrigé.

tabindex attribute | tabIndex. Internet Explorer Dev Center