Keyboard Navigation Patterns for React Components

Keyboard navigation in React uses Tab to move between components and arrow keys to move inside them. Learn the roving tabindex pattern.

5 min read

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.

App.jsxApp.jsx
<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.

App.jsxApp.jsx
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

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.
RunePowered by Rune AI

Frequently Asked Questions

Which key moves between components?

Tab and Shift+Tab move focus between components in the tab sequence. Arrow keys move focus inside a component that has multiple focusable items.

What is roving tabindex?

Roving tabindex keeps one item in a group focusable with tabIndex 0 while the rest use -1. Arrow keys move focus and move the 0 to the newly focused item.

When should a disabled control stay focusable?

Use the disabled attribute when a user can infer the disabled state from nearby controls. Use aria-disabled when the control must stay discoverable, like a disabled menu item.

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.