michael jones
michael jones

Reputation: 740

How To Make A Tab Loop On HTML Form

When a user tabs through form input boxes it goes in order. I figured out that you could order them though when using tabindex=x. I have 5 inputs on my form, so I have tabindex 5 different times. After that it goes to different items on the page, so is there a way to make it just loop through those 5 items? By the way I can not use tabindex=0 because then I would have to add that to 100s of items. So basically my question is how can I make a so called "tab loop".

Upvotes: 1

Views: 7973

Answers (3)

robert Neyrinck
robert Neyrinck

Reputation: 11

As a follow up to @NicolasBernier JqueryUI answer, this is the code that worked w/o the ':tabbable' keyword.

// first block deals with first tabbable element
$('uniqueContainerOfElementInQuestion').find('firstTabbableElement(ex."a")').first().on('keydown', function (e) {

// first ele w/ shift and tab
    if (e.shiftKey == true && e.keyCode == 9) {
        console.log('Shift tab on first')
        e.preventDefault();
        // focus on element
        // if it isn't working uncomment out timeout as possible test/quickfix
        // setTimeout(()=>{
  $('uniqueContainerOfElementInQuestion').find('lastTabbableElement(ex."button")').last().focus();
        // })
    }
});
$('uniqueContainerOfElementInQuestion').find('lastTabbableElement(ex."button")').last().on('keydown', function (e) {

    // Leaving the last element with Tab : focus the first one
    if (e.shiftKey == false && e.keyCode == 9) {
        console.log('tab on last')
        e.preventDefault();
        // setTimeout(()=>{

        $('uniqueContainerOfElementInQuestion').find('firstTabbableElement(ex."a")').first().focus();
        // })
    }
});

Upvotes: 1

NicolasBernier
NicolasBernier

Reputation: 1606

I found an easy way to achieve this using jQueryUI. I created a .tabloop class and I'm using the following snippet.

The :tabbable selector is not natively included in jQuery, it's part of jQueryUI but you can easily make your own.

// Focus loop inside element with class tabloop
$(function() {
  $(document).on('keydown', '.tabloop :tabbable:not([readonly])', function(e) {

    // Tab key only (code 9)
    if (e.keyCode != 9)
      return;

    // Get the loop element
    var loop = $(this).closest('.tabloop');

    // Get the first and last tabbable element
    var firstTabbable = loop.find(':tabbable:not([readonly])').first();
    var lastTabbable = loop.find(':tabbable:not([readonly])').last();

    // Leaving the first element with Tab : focus the last one
    if (firstTabbable.is(e.target) && e.shiftKey == true) {
      e.preventDefault();
      lastTabbable.focus();
    }

    // Leaving the last element with Tab : focus the first one
    if (lastTabbable.is(e.target) && e.shiftKey == false) {
      e.preventDefault();
      firstTabbable.focus();
    }
  });
});
.tabloop {
  border: 1px red solid;
  padding: 1ch;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<p>
  <label for="text1">Field 1:</label>
  <input type="text" id="text1">
</p>

<p>
  <label for="text2">Field 2:</label>
  <input type="text" id="text2">
</p>

<p>
  <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank">Link</a>
</p>

<p>
  <button type="button">Button</button>
</p>

<div class="tabloop">

  <p>
    <label for="text3">Field 3:</label>
    <input type="text" id="text3">
  </p>

  <p>
    <label for="text4">Field 4:</label>
    <input type="text" id="text4">
  </p>

  <p>
    <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank">Link</a>
  </p>

  <p>
    <button type="button">Button</button>
  </p>
</div>

Upvotes: 1

Touffy
Touffy

Reputation: 6561

You can't declaratively set up a tab loop. That feature is designed to work within the normal tabbing behavior of the browser, which is to visit all tab-able elements in both the page and the browser chrome.

If you want to prevent tabbing away from a chosen subset of elements, you'll need a little JavaScript and you better know very well why you're doing it and what it'll break, give some visual cues that the form is focused to the detriment of the rest of the UI, and think of some non-visual clients for whom keyboard navigation is even more important.

Assuming that you have indeed knowingly judged that it's OK to hijack tabbing, one relatively safe way to do this is to create a dummy tabbable element (has to be displayed, but could be practically invisible) with a tabIndex that makes it the next after the last item in your form, and another right before the first in your form.

dummyItemBeforeForm.addEventListener('focus', function(e){
  lastItemOfMySuperImportantForm.focus() }, true )

dummyItemAfterForm.addEventListener('focus', function(e){
  firstItemOfMySuperImportantForm.focus() }, true )

That will make the focus loop back to the beginning of the form when tabbing away from the last item, and loop to the end when shift-tabbing from the first.

Make sure that the dummy items are disabled by default and only become focusable once the user focuses your form and gets the visual cues that the form is now kind of modal, and disable the dummies again once the user is done with the form.

And please, please, test this with real users, and see if they like it or if they panic because you broke their expected tab behavior.

Upvotes: 2

Related Questions