Roving tab index (RTI) manages keyboard focus across groups of interactive elements.
It automatically handles <a> and <button> elements, supports arbitrarily nested groups with boundary-based scoping, and provides full keyboard navigation support.
All <a> and <button> elements are automatically treated as RTI targets. Other elements can become targets by using the rti directive.
RTI has the concept of groups delineated by boundaries. There is a default "root" group under which all RTI targets and other groups reside. This group is automatically managed and does not require a declared boundary. Specific groups can be created using the rtiBoundary. These groups can be arbitrarily deeply nested. A group boundary is automatically treated as an RTI target.
Boundaries are given unique anonymous IDs unless a value is passed to rtiBoundary. Targets are considered in the group of the nearest ancestor that is an rtiBoundary. This can be overridden by passing a group ID to rti but this is only valid if the boundary has also been given a name.
<div rti>I get tabbed to first</div>
<div rti>I get tabbed to second</div>
<button>I'm a button that defaults to the root group</button>
<div rtiBoundary="group">
<div rti="group">I only get tabbed to if space is hit on this group</div>
<div rti="group">Use arrow keys to navigate around in the group</div>
<a>I'm an anchor that defaults to the outer group</a>
<div rtiBoundary="nested">
<div rti="nested">You have to hit space again to get to me</div>
<button>I'm a button that defaults to the inner group</button>
<div rti="nested">You can hit escape to return to the previous group</div>
</div>
<div rtiBoundary>
<div rti>Everything in here uses autogenerated groups</div>
<div rti>Does it work?</div>
<button>It does!</button>
<a>Let's goooooo</a>
</div>
</div>
| Key | Action |
|---|---|
| Tab / Shift+Tab | Moves focus between RTI targets |
| ↑ / ↓ | Moves focus between targets within a group |
| Space | Enters the focused group |
| ESC | Leaves the current group |
Note: the parent group isn't necessarily the containing group in the DOM. Overriding boundary and target values can produce an RTI hierarchy that differs from the DOM tree.