IndigoWhiteGun
by SimonCurtis
HTML
<div>
<button id="toggle-run" tabindex="-1">Start</button>
<input id="element-5" type="text">
<input id="element-1" type="text" tabindex="1">
<input id="element-2" type="text" tabindex="2">
<input id="element-4" type="text">
</div>
<!-- The focus order should be [element-2, element-1, element-5, element-4] -->
CSS
input:focus {
background: red;
}
JavaScript
// Find all the elements that have a tabindex set, I would keep this file scoped for performance sake
const tabElements = Array.from(document
.querySelectorAll('a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])'))
.reduce((prev, next) => {
return next.tabIndex > 0
? [[...prev[0], next], prev[1]]
: [prev[0],[...prev[1], next]];
}, [[], []])
.reduce((prev, next) => ([...prev, ...next.sort((a, b) => a.tabIndex === 0 ? -1 : a.tabIndex > b.tabIndex ? -1 : 1)]), []);
const expectedOrder = ["element-2", "element-1", "element-5", "element-4"];
console.log("Expected order correct?", tabElements.every((element, index) => expectedOrder[index] === element.id))
// Method to find the next element to focus and change the focus to that element
const DispatchTab = () => {
const currentIndex = tabElements.findIndex(e => e === document.activeElement);
// get the next element in the list, "%" will loop around to 0
const nextIndex = (currentIndex + 1) % tabElements.length;
tabElements[nextIndex].focus();
}
// Interval just to call above method
let interval = {};
document.getElementById("toggle-run").addEventListener("click", e => {
if (e.target.innerText === "Stop"){
clearInterval(interval);
e.target.innerText = "Start";
}
else {
interval = setInterval(DispatchTab, 1000);
e.target.innerText = "Stop";
}
});