60

I want to detect the focus event of an element, but only if it was initiated by the user pressing the tab key. For example:

<input type="text" id="foo" />
<input type="text" id="detect" />

If the user is focused on #foo and presses Tab, I want the event to fire once #detect becomes focused (or a conditional inside the focus event to be true). Conversely, if the user simply clicks on the #detect field to focus it, I do not want the event to fire (or I want the conditional inside the focus event call to be false).

I don't want to use the keydown event of #foo and check if the tab key was pressed, as I want the approach to be independent of any other element.

I looked through the console output of the following code, but couldn't notice any real differences between the two methods of focusing:

$('#detect').on('focus', function(e){
   console.log(e); 
});

(fiddle)

Is this possible to accomplish in a relatively simple way?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
HellaMad
  • 5,294
  • 6
  • 31
  • 53

5 Answers5

57

I know you have accepted an answer but you could test the button pressed using the following:

$('#detect').on('focus', function(e){
    $(window).keyup(function (e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if (code == 9) {
           alert('I was tabbed!');
        }
    });
});

http://jsfiddle.net/LPGLm/1/

Edit: change the listener around:

$(window).keyup(function (e) {
    var code = (e.keyCode ? e.keyCode : e.which);
    if (code == 9 && $('#detect:focus').length) {
        alert('I was tabbed!');
    }
});

http://jsfiddle.net/LPGLm/7/

Pete
  • 57,112
  • 28
  • 117
  • 166
  • Hm, this actually seems like a better solution.. I unselected the answer, I'll hold off on selecting for now. – HellaMad Apr 22 '13 at 10:43
  • 6
    You might be on to something, but you're not there. *Every time* `#detect` gains focus, a global event listener will be registered, that looks for a tab *anywhere*. So if focus and blur `#detect` three times by clicking in and outside it, blur it, and then hit tab so that `#foo` gains focus, you'll still get three "I was tabbed" alerts. – David Hedlund Apr 22 '13 at 11:21
  • Have changed the answer for a better way to do it – Pete Apr 22 '13 at 11:36
12

A more responsive solution would be to use two listeners:

var mousedown = false;
$('#detect').on('mousedown', function () {
    mousedown = true;
});

$('#detect').on('focusin', function () {
    if(!mousedown) {
        // logic
    }
    mousedown = false;
});

Fiddle showing the difference in speed:

http://jsfiddle.net/u2y45/1/

Gary
  • 634
  • 6
  • 10
1

As you've noticed, the event object itself does not distinguish the means of access. What you can do is to bind a mousedown listener, which will fire before focus, and set some timestamp flag that you compare to some threshold value in your focus handler.

David Hedlund
  • 128,221
  • 31
  • 203
  • 222
  • Hmmm, that's actually pretty clever. Didn't think of that, thanks. – HellaMad Apr 22 '13 at 10:26
  • Note that this distinguishes between tab and click, but it will not help you distinguish tab from `.focus()`, but then I don't know if that's somethin you want. If you do want that, perhaps you could implement a global keyup listener for `tab` and compare the proximity between the latest tab and your focus event, but that seems... arduous. – David Hedlund Apr 22 '13 at 10:29
  • It does indeed seem arduous. I'm not worried about `.focus()` triggering my event, so everything should work as you originally pointed out. Thanks again! – HellaMad Apr 22 '13 at 10:34
1

I use the following:

(function() {
  const tabHistory = [];

  window.addEventListener('keyup', function (e) {
    const code = e.keyCode || e.which;
    const index = tabHistory.length === 0 ? 1 : tabHistory.length + 1;

    if (code == 9) {
      tabHistory.push({
        element: e.target,
        index
      });

      console.log(index, e.target, tabHistory);
    }
  });
})();

I recommend keeping a track of the focused elements, this way you make sure the user will be able to tab as you expected.

Console Screenshot

Hope it helps!

Esteban Borai
  • 2,311
  • 1
  • 21
  • 27
  • I think this is the better answer, because of the "target" piece, which you can use to match any target in a more generalizable way. – NovaDev Jul 21 '23 at 14:55
0

You can check focus event on specific input by this code

$(window).on('keyup', function(event){
    if(event.keyCode == '9'){

      getFocused(event);
    }

})
var focused = 0;
function getFocused(e){
var ida =  $(':focus').eq(0).prop('id');
    if(ida=='detect' && focused==0){
        focused = 1;
        console.log(e);
    }
}

(fiddle)