Keyboard navigation patterns in React describe how focus moves with the Tab key and the arrow keys. Tab moves between components, arrows move inside a component, and a roving tabindex keeps one item in the tab order at a time.
Tab moves between components
Pressing Tab moves focus through the tab sequence, and Shift+Tab moves backward. Native links and form controls are already in that sequence, while other elements join it only when they carry a tabIndex attribute.
- tabIndex 0 puts an element in the tab sequence at its DOM position.
- tabIndex -1 makes an element focusable by code but not by Tab.
- Positive values reorder the sequence and are best avoided.
Positive tabIndex values make the order hard to predict, so almost all code should only use 0 and -1. Keep the sequence in DOM order so the keyboard path matches what screen readers read.
Arrows move inside a component
A widget with several focusable items should put only one of them in the tab sequence. Once focus lands on it, the arrow keys move among the items, and Tab leaves the widget. Radio groups, tab lists, menus, and lists all follow this convention.
Which arrow key to use follows the widget: a vertical list uses ArrowDown and ArrowUp, while a tab list uses ArrowLeft and ArrowRight.
Roving tabindex
Roving tabindex is the standard way to move the tab entry point as focus moves. The focused item has tabIndex 0, and every other item has -1. Each option also needs aria-selected, and the list itself needs role="listbox" for the pattern to be complete.
<li
role="option"
aria-selected={index === active}
tabIndex={index === active ? 0 : -1}
>
{item.name}
</li>Inside a list, active is the current index in state. When the user presses an arrow key, the handler updates active, and the newly focused item becomes the one Tab will return to.
function moveFocus(e, index) {
if (e.key === "ArrowDown") {
e.preventDefault();
setActive(index + 1);
}
}ArrowDown moves the active index down one, and the previous item's tabIndex flips back to -1. The browser scrolls the newly focused item into view for free.
Keep focus visible and predictable
Never let focus disappear. When a dialog closes, return focus to the button that opened it. When a focused row is deleted, move focus to the next row or a sensible neighbor.
If focus ever drops to the body, keyboard users have lost their place. A visible focus indicator makes every move obvious, so users never have to guess where they landed.
What to learn next
The keys a single control should handle are covered in handling keyboard events, and making clickable elements accessible explains when a native button already does the job.
Rune AI
Key Insights
- Tab and Shift+Tab move between components.
- Arrow keys move focus inside composite widgets.
- Roving tabindex keeps one item at tabIndex 0.
- Use -1 for items reached programmatically.
- Keep focus visible and return it after dialogs.
Frequently Asked Questions
Which key moves between components?
What is roving tabindex?
When should a disabled control stay focusable?
Conclusion
Tab moves between components, arrows move inside them, and roving tabindex keeps one item in the tab order. Manage focus so it stays visible and predictable.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.