How to detect `focusin` support?
Asked Answered
I

3

13

Thanks to Perfection kills, we can use the following JavaScript to detect event support:

function hasEvent(ev) {
    var elem = document.createElement('a'),
        type = 'on' + ev,
        supported = elem[type] !== undefined;
    if (!supported) {
        elem.setAttribute(type, 'return;');
        supported = typeof elem[type] === 'function';
    }
    elem = null;
    return supported;
}

This works for about the only time I need it: detecting mouseenter support; hasEvent('mouseenter') will return false in Chrome, Firefox, etc., as it should.

But now I'm trying to "fix" browsers that don't support the focusin and focusout events. According to PPK, that's basically just Firefox. Unfortunately, Chrome and Safari are listed as having "incomplete" support, for the following reason:

Safari and Chrome fire these events only with addEventListener; not with traditional registration.

In general, that's fine; I'd only be using addEventListener anyway. It does mean, however, that detecting support via elem.onfocusin !== undefined won't work. I tested it out, and it's true:

<p>Do I support <a href="#">focusin</a>?</p>

<script>
var elem = document.getElementsByTagName('p')[0];

// hasEvent method defined here
function listener() {
    var response = hasEvent('focusin') ? 'Yes!' : 'No...';
    alert(response);
}

elem.addEventListener('focusin', listener, false);
</script>

The above alerts No... in Chrome! Is there any way to detect whether the browser supports focusin, without using browser sniffing?

Inkhorn answered 7/9, 2011 at 16:56 Comment(3)
is there a difference between mouseenter & mouseover? or focusin & focus? or focusout & blur?Kopje
@Kopje mouseenter doesn't bubble, while mouseover does; focusin/focusout do bubble, focus/blur don't.Inkhorn
Another important fact is that focusin and focusout event objects have the relatedTarget property which points to the element that has lost/received focus.Clench
D
3

This uses the fact that calling focus() triggers focusin: http://jsfiddle.net/pimvdb/YXeD3/.

The element must be visible and inserted into the DOM, otherwise focusin is not fired for some reason.

var result = (function() {
    var hasIt = false;

    function swap() {
        hasIt = true; // when fired, set hasIt to true
    }

    var a = document.createElement('a'); // create test element
    a.href = "#"; // to make it focusable
    a.addEventListener('focusin', swap, false); // bind focusin

    document.body.appendChild(a); // append
    a.focus(); // focus
    document.body.removeChild(a); // remove again

    return hasIt; // should be true if focusin is fired
})();
Disassociate answered 7/9, 2011 at 17:15 Comment(2)
I like the idea but this detection method is a bit obstrusive as it changes the active element on the page.Adalineadall
This answer would be made better if it also prevented the temporary anchor element from receiving focus. Then it would have no observable side effects. (Like stealing focus. What if an element on the page tried to autofocus when the page loads?)Obeded
T
4

focusin & focusout should be fired BEFORE target element receives focus, event order is also seems buggy

http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order

currently, only IE works according to spec:

Chrome/Safari:
focus
focusin
DOMFocusIn
blur
focusout
DOMFocusOut
focus
focusin
DOMFocusIn

Opera 12:
focus
DOMFocusIn
focusin
blur
DOMFocusOut
focusout
focus
DOMFocusIn
focusin

IE 8:
focusin
focus
focusout
focusin
blur
focus

Firefox 14:
focus
blur
focus
Torrefy answered 30/7, 2012 at 13:36 Comment(2)
Well, spec has been written following IE's behavior, so it's not really surprising.Gouty
but IE behavior is good, ie support event.toElement/event.fromElement, other browsers doesn't support relativeTarget/toElement/fromElement for this eventTorrefy
D
3

This uses the fact that calling focus() triggers focusin: http://jsfiddle.net/pimvdb/YXeD3/.

The element must be visible and inserted into the DOM, otherwise focusin is not fired for some reason.

var result = (function() {
    var hasIt = false;

    function swap() {
        hasIt = true; // when fired, set hasIt to true
    }

    var a = document.createElement('a'); // create test element
    a.href = "#"; // to make it focusable
    a.addEventListener('focusin', swap, false); // bind focusin

    document.body.appendChild(a); // append
    a.focus(); // focus
    document.body.removeChild(a); // remove again

    return hasIt; // should be true if focusin is fired
})();
Disassociate answered 7/9, 2011 at 17:15 Comment(2)
I like the idea but this detection method is a bit obstrusive as it changes the active element on the page.Adalineadall
This answer would be made better if it also prevented the temporary anchor element from receiving focus. Then it would have no observable side effects. (Like stealing focus. What if an element on the page tried to autofocus when the page loads?)Obeded
A
0

You can test for ("onfocusin" in document).

This method has the advantage of being light and unobtrusive and it will tell you whether the browser supports the focusin event. (not on Chrome, sorry)

You may use the following code to get the same behaviour as the focusin event on all browsers (IE9+, Chrome, Firefox, Edge):

var eventName, useCapture;
if ("onfocusin" in document) {
  eventName = "focusin";
  useCapture = false;
} else {      
  eventName = "focus";
  useCapture = true;
}

document.body.addEventListener(eventName, function( event ) {
    event.target.style.background = "pink";    
  }, useCapture);

JS fiddle here: https://jsfiddle.net/d306qm92/2/

More information about the Firefox workaround here: https://developer.mozilla.org/en-US/docs/Web/Events/focus#Event_delegation

UPDATE: As said above, the test will wrongly say "false" on Chrome, nonetheless the code sample will work as intended as Chrome supports both methods (focusin and focus with useCapture).

Adalineadall answered 29/4, 2016 at 13:3 Comment(1)
It doesn't matter about Chrome, because with Chrome you won't have the need to use focusin and focus. for example the js addEventListener visibilitychangeLynnelle

© 2022 - 2024 — McMap. All rights reserved.