Enter key press behaves like a Tab in Javascript

165,094

Solution 1

I used the logic suggested by Andrew which is very effective. And this is my version:

$('body').on('keydown', 'input, select', function(e) {
    if (e.key === "Enter") {
        var self = $(this), form = self.parents('form:eq(0)'), focusable, next;
        focusable = form.find('input,a,select,button,textarea').filter(':visible');
        next = focusable.eq(focusable.index(this)+1);
        if (next.length) {
            next.focus();
        } else {
            form.submit();
        }
        return false;
    }
});

KeyboardEvent's keycode (i.e: e.keycode) depreciation notice :- https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode

Solution 2

The simplest vanilla JS snippet I came up with:

document.addEventListener('keydown', function (event) {
  if (event.keyCode === 13 && event.target.nodeName === 'INPUT') {
    var form = event.target.form;
    var index = Array.prototype.indexOf.call(form, event.target);
    form.elements[index + 1].focus();
    event.preventDefault();
  }
});

Works in IE 9+ and modern browsers.

Solution 3

Map [Enter] key to work like the [Tab] key

I've rewritten Andre Van Zuydam's answer, which didn't work for me, in jQuery. This caputures both Enter and Shift+Enter. Enter tabs forward, and Shift+Enter tabs back.

I've also rewritten the way self is initialized by the current item in focus. The form is also selected that way. Here's the code:

// Map [Enter] key to work like the [Tab] key
// Daniel P. Clark 2014

// Catch the keydown for the entire document
$(document).keydown(function(e) {

  // Set self as the current item in focus
  var self = $(':focus'),
      // Set the form by the current item in focus
      form = self.parents('form:eq(0)'),
      focusable;

  // Array of Indexable/Tab-able items
  focusable = form.find('input,a,select,button,textarea,div[contenteditable=true]').filter(':visible');

  function enterKey(){
    if (e.which === 13 && !self.is('textarea,div[contenteditable=true]')) { // [Enter] key

      // If not a regular hyperlink/button/textarea
      if ($.inArray(self, focusable) && (!self.is('a,button'))){
        // Then prevent the default [Enter] key behaviour from submitting the form
        e.preventDefault();
      } // Otherwise follow the link/button as by design, or put new line in textarea

      // Focus on the next item (either previous or next depending on shift)
      focusable.eq(focusable.index(self) + (e.shiftKey ? -1 : 1)).focus();

      return false;
    }
  }
  // We need to capture the [Shift] key and check the [Enter] key either way.
  if (e.shiftKey) { enterKey() } else { enterKey() }
});

The reason textarea

is included is because we "do" want to tab into it. Also, once in, we don't want to stop the default behavior of Enter from putting in a new line.

The reason a and button

allow the default action, "and" still focus on the next item, is because they don't always load another page. There can be a trigger/effect on those such as an accordion or tabbed content. So once you trigger the default behavior, and the page does its special effect, you still want to go to the next item since your trigger may have well introduced it.

Solution 4

Thank you for the good script.

I have just added the shift event on the above function to go back between elements, I thought someone may need this.

$('body').on('keydown', 'input, select, textarea', function(e) {
var self = $(this)
  , form = self.parents('form:eq(0)')
  , focusable
  , next
  , prev
  ;

if (e.shiftKey) {
 if (e.keyCode == 13) {
     focusable =   form.find('input,a,select,button,textarea').filter(':visible');
     prev = focusable.eq(focusable.index(this)-1); 

     if (prev.length) {
        prev.focus();
     } else {
        form.submit();
    }
  }
}
  else
if (e.keyCode == 13) {
    focusable = form.find('input,a,select,button,textarea').filter(':visible');
    next = focusable.eq(focusable.index(this)+1);
    if (next.length) {
        next.focus();
    } else {
        form.submit();
    }
    return false;
}
});

Solution 5

This worked for me:

$(document).on('keydown', ':tabbable', function(e) {

    if (e.key === "Enter") {
        e.preventDefault();

        var $canfocus = $(':tabbable:visible');
        var index = $canfocus.index(document.activeElement) + 1;

        if (index >= $canfocus.length) index = 0;
        $canfocus.eq(index).focus();
    }

});
Share:
165,094

Related videos on Youtube

Ross
Author by

Ross

Updated on July 05, 2022

Comments

  • Ross
    Ross almost 2 years

    I'm looking to create a form where pressing the enter key causes focus to go to the "next" form element on the page. The solution I keep finding on the web is...

     <body onkeydown="if(event.keyCode==13){event.keyCode=9; return event.keyCode}">
    

    Unfortunately, that only seems to work in IE. So the real meat of this question is if anybody knows of a solution that works for FF and Chrome? Additionally, I'd rather not have to add onkeydown events to the form elements themselves, but if that's the only way, it will have to do.

    This issue is similar to question 905222, but deserving of it's own question in my opinion.

    Edit: also, I've seen people bring up the issue that this isn't good style, as it diverges from form behavior that users are used to. I agree! It's a client request :(

  • Ross
    Ross almost 15 years
    Normally I would agree, but our app lets users set stuff like this separately for their own accounts, and the client is offering money for it, so I don't think we can justify holding our ground.
  • Joel Purra
    Joel Purra about 12 years
    Short and concise! Started off with something similar as well, but now I've expanded on it - see my answer (on this page) with PlusAsTab.
  • aimfeld
    aimfeld almost 11 years
    I suggest removing textarea from the selector in the first line. In a textarea, you want to be able to start a new line using the enter key.
  • Mike Bethany
    Mike Bethany over 9 years
    I've found that pressing enter for submit is NOT expected and in fact is highly annoying. In fact in every single website I've ever built the client has asked me to change this behavior as it is unwanted. I blame someone [cough]Microsoft[/cough] that can't admit they made a bad choice for this continued behavior in the face of overwhelming evidence that it's not wanted.
  • AVProgrammer
    AVProgrammer about 8 years
    What is the purpose of the last bit: if (e.shiftKey) { enterKey() } else { enterKey() }? Seems like it should just be: enterKey().
  • 6ft Dan
    6ft Dan about 8 years
    @AVProgrammer To have enter act like tab it needs to go in reverse if the shift key is held. The line you asked about allows the enter key to be checked for while the shift key is depressed.
  • SnakeDrak
    SnakeDrak about 8 years
    I suggest ignore fields with readonly and disabled: filter(':visible:not([readonly]):enabled')
  • Vishal_Kotecha
    Vishal_Kotecha almost 8 years
    I know this is a very old thread but with this code, how do we allow default behavior of <input type="button"/> ? how to allow button to be clicked with enter key?
  • aruno
    aruno over 7 years
    Was specifically looking for something to steal that considered invisible fields. Most other solutions I found don't. Thanks
  • Jeppe Andreasen
    Jeppe Andreasen over 6 years
    it doesn't make sense to check for e.shiftKey and call enterKey in both cases.
  • 6ft Dan
    6ft Dan over 6 years
    @JeppeAndreasen If you want it to behave like tab then yes it does. Because Shift+Tab goes in the reverse direction.
  • Jeppe Andreasen
    Jeppe Andreasen over 6 years
    Youre performing the same action regardless if shift is pressed or not. So the if statement is not necessary, as avprogrammer has also pointed out
  • 6ft Dan
    6ft Dan over 6 years
    AVProgrammer was asking, not stating. I've tested the code in my own browser and without the if statement it won't work when shift is held down.
  • Carles S
    Carles S almost 5 years
    Could you please provide with a small explanation of the code to make the answer more understandably ?
  • user11706828
    user11706828 almost 5 years
    firstly you need to select all input fields in form and then you need to bind keypress event in every input fields , then you need to check whether enter keypress or not and when enter key is press in an input field you need to get index of this input field and add increment to index of it to find next input field and when you find next input field you need to focus on it....!
  • isherwood
    isherwood over 4 years
    This doesn't seem to be working. The fiddle link is dead (and has been removed).
  • Mat Mannion
    Mat Mannion almost 4 years
    This will require jquery-ui for the tabbable selector
  • LittleTreeX
    LittleTreeX over 3 years
    While this code might "work" for you, please take note that it is not correctly written, and as such, if you attempt to amend it in anyway, you are going to face problems. For ONE: $.inArray(self, focusable) returns the INDEX of the found element within the array, and -1 if it is not found. Thus, If ($.inArray(self, focusable)) will not function the way you expect, and will generally always pass. In fact, it does always pass because you cannot compare these jquery objects in this manner, and thus it always returns -1 !
  • Ali Ahmad Pasa
    Ali Ahmad Pasa about 3 years
    I have used your example there is a one issue for select2 field it reset the focus to first field. Any idea how to fix it?