Roving Tabindex - Menu example
by tohuwabohu_io
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Roving Tabindex - Menu example</title>
</head>
<body>
<main>
<h1>Awesome Website</h1>
<div>
<h2>Navigation</h2>
<ul role="menu">
<li role="menuitem">
<a href="#" tabindex="0">Home</a>
</li>
<li role="menuitem">
<a href="#" tabindex="-1">Archive</a>
</li>
<li role="menuitem">
<a href="#" tabindex="-1">Search</a>
</li>
<li role="menuitem">
<a href="#" tabindex="-1">About</a>
</li>
<li role="menuitem">
<a href="#" tabindex="-1">Imprint</a>
</li>
<li role="menuitem">
<a href="#" tabindex="-1">Twitter</a>
</li>
<li role="menuitem">
<a href="#" tabindex="-1">GitHub</a>
</li>
</ul>
</div>
<div>
<h2>Content</h2>
<label for="name">Name:</label>
<input id="name" type="text">
</div>
</main>
</body>
</html>
JavaScript
document.addEventListener('DOMContentLoaded', () => {
const links = Array
.from(document.querySelectorAll("ul[role=menu] > li > a"));
links.forEach(link => {
link.addEventListener('keydown', (e) => {
console.log(e.key);
if (e.key !== 'Tab' && e.key !== 'Enter') {
e.preventDefault();
}
const menu = Array
.from(document.querySelectorAll("ul[role=menu] > li > a"));
const thisIndex = menu.indexOf(e.target);
switch (e.key) {
case 'ArrowUp': {
roveTabindex(menu, thisIndex, -1);
}
break;
case 'ArrowDown': {
roveTabindex(menu, thisIndex, 1);
}
break;
default:
return;
}
});
});
});
const roveTabindex = (menu, index, inc) => {
let nextIndex = index + inc;
if (nextIndex < 0) {
nextIndex = menu.length - 1;
} else if (nextIndex >= menu.length) {
nextIndex = 0;
}
console.log(`roving tabindex to index ${nextIndex}`);
menu[index].setAttribute("tabindex", "-1");
menu[nextIndex].setAttribute("tabindex", "0");
menu[nextIndex].focus();
}