I want to restrict the focus to a single form when tab is pressed.
By that I mean focus on form 1's tab index 1, 2, and 3, and then move back to 1 within the same form, then 2, etc., never going to form 2's inputs. I also don't want to change the tab indices.
<form style="background-color:red">
<input tabindex="01"/>
<input tabindex="02"/>
<input tabindex="03"/>
</form>
<form style="background-color:blue">
<input tabindex="01"/>
<input tabindex="02"/>
<input tabindex="03"/>
</form>
This isn't good practice, so don't do it unless there is really good reason to do it...
But there's no built in HTML way to do this, so we need to use some JavaScript along with a custom data attribute.
I think it's easiest to use a data attribute to the parent (the <form>
) so that way we don't have to add it to each input individually. I named mine data-tabgroup
.
Then we need some JS:
// Select the tab groups based on the data attribute we added
var tabgroups = document.querySelectorAll("[data-tabgroup]");
// Loop through each to attach the listeners we need
for (var i = 0; i < tabgroups.length; i++) {
var inputs = tabgroups[i].querySelectorAll("[tabindex]");
// Loop through all of the elements we want the tab to be changed for
for (var j = 0; j < inputs.length; j++) {
// Listen for the tab pressed on these elements
inputs[j].addEventListener("keydown", function(myIndex, inputs, e) {
if (e.key === "Tab") {
// Prevent the default tab behavior
e.preventDefault();
// Focus the next one in the group
if (inputs[myIndex + 1]) {
inputs[myIndex + 1].focus();
} else { // Or focus the first one again
inputs[0].focus();
}
}
}.bind(null, j, inputs)) // Make a copy of the variables to use in the addEventListener
}
}
<form style="background-color: red" data-tabgroup>
<input tabindex="01" />
<input tabindex="02" />
<input tabindex="03" />
</form>
<form style="background-color: blue" data-tabgroup>
<input tabindex="01" />
<input tabindex="02" />
<input tabindex="03" />
</form>
And that's it! Here's the demo.
Some notes:
tabindex
within the group (it just selects the next one in the HTML). To take that into account, you just need to put the elements in the array in order of their tabindexes or sort them by the tabindexes after you add them to the array.tabindex
be applied to children that you want this to affect. If you want it to apply to all inputs by default, just change the querySelectorAll
value for inputs
to input
. If you want something more complex, you'll have to change it as needed.