Keyboard and Focus Patterns
Arrow Key Roving Focus
A tiny toolbar keeps one button in the tab order and moves focus to the next button on ArrowRight.
Program
Roving tabindex can stay small: one item has tabindex 0, the others have -1, and one ArrowRight press moves focus to the next item.
arrow_key_roving_focus.html
Visuals: captured from real browser rendering
<div role="toolbar" aria-label="Text tools" id="text-tools">
<button tabindex="0">Bold</button>
<button tabindex="-1">Italic</button>
<button tabindex="-1">Underline</button>
</div>
<p id="toolbar-status" role="status">Bold focused.</p>
<style>
#text-tools button:focus-visible { outline: 3px solid #2563eb; outline-offset: 2px; }
</style>
<script>
const toolbar = document.querySelector("#text-tools");
const buttons = [...toolbar.querySelectorAll("button")];
const toolbarStatus = document.querySelector("#toolbar-status");
let activeIndex = 0;
toolbar.addEventListener("keydown", event => {
if (event.key !== "ArrowRight") return;
event.preventDefault();
activeIndex = Math.min(buttons.length - 1, activeIndex + 1);
buttons.forEach((button, index) => {
button.tabIndex = index === activeIndex ? 0 : -1;
});
buttons[activeIndex].focus();
toolbarStatus.textContent = `${buttons[activeIndex].textContent} focused.`;
});
</script>
Create a small toolbar.

The three buttons are grouped as one small toolbar. Start with one tabbable button.

Only Bold starts in the normal tab order. Listen for ArrowRight.

The toolbar listens for one bounded arrow-key move. Update the active index.

The next index moves from Bold to Italic without passing the end. Move the tabbable item.

The tab order changes so only the new item has tabindex 0. Render focus on the next button.

The visible focus moves to the next toolbar button. Confirm the focused button.

The status text confirms which toolbar button is active.
toolbar
A toolbar groups a short set of related controls.
roving tabindex
Only the active item has tabindex 0; inactive items use -1.
bounded arrow key
ArrowRight moves one step but never past the last button.