15

I am trying to set a listener that listens for all focus events. In particular I am trying to listen for anytime an input or textbox gains focus. Per some research, the widely accepted way to achieve this is like this:

document.body.onfocus = function(event) {
   //Check the event.target for input/textbox
   //Do something
};

But the document.body.onfocus doesn't seem to fire, ever. I thought it might be because the document doesn't actually ever receive focus so I tried:

document.body.focus();

To initially "set" the focus, but this doesn't work either.

Any ideas on how I can listen to a focus event on all inputs/textboxes without actually setting the event directly on the element itself? Vanilla javascript only please, I am not using a framework.

Per the accepted answer here is some working code:

var focusHandler = function(event) {
    var type = event.target.nodeName.toLowerCase();
    if(type == 'input' || type == 'textarea') {
        //Do something
    }
};
document.body.addEventListener('focus', focusHandler, true); //Non-IE   
document.body.onfocusin = focusHandler; //IE
ryandlf
  • 27,155
  • 37
  • 106
  • 162
  • Where are you running this code? In the ``? Or somewhere in the ``? I don't think the `document.body` will be available when running code in the ``...not sure though – Ian Apr 08 '13 at 14:41
  • A separate js file. Not in the html at all. – ryandlf Apr 08 '13 at 14:41
  • But where is the JS file being included in your HTML? – Ian Apr 08 '13 at 14:42
  • The body. I use document.body all the time for click events on the body so that is not the issue. – ryandlf Apr 08 '13 at 14:43
  • 1
    http://stackoverflow.com/questions/5574207/javascript-which-events-do-not-bubble - it doesn't bubble – Ian Apr 08 '13 at 14:44

2 Answers2

13

As some events (focus, blur, change) do not bubble up, I would recommend you to try Event Capturing instead. First of all onfocus will not work for this, so you have to use addEventListener where you are able to specifiy the used delegation mode in the third argument. Look at MDN for the use of addEventListener.

And take a look at this article for further information about delegating the focus event up.

user1983983
  • 4,793
  • 2
  • 15
  • 24
  • Works beautifully. Great article as well. I always wondered what that false at the end of an eventListener did! Updating OP with some working code. – ryandlf Apr 08 '13 at 15:06
  • 7
    This answer should include the relevant information behind these links, e.g. that event capturing is enabled with the third argument in `parentElement.addEventListener("focus", listener, true)` being `true`. – Sebastian Simon Aug 10 '18 at 16:19
7

The focus event doesn't bubble from elements up to their ancestor elements, so you can't use event delegation (hooking it on body and seeing it for all descendants of body) to detect it.

There's a newer event, focusin (a Microsoft innovation, now also available in other browsers), which does bubble, so that may work for you depending on which browsers you want to support.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    See this interesting article for further information and a nice hack: http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html – Marcus Ilgner Apr 08 '13 at 14:46
  • 1
    And of course, if you're open to using libraries, jQuery makes `focus` and `blur` bubble in a cross-browser way without your having to worry about it. – T.J. Crowder Apr 08 '13 at 14:48