RovingFocusGroup provides a robust implementation of the roving tabindex pattern, allowing users to navigate through a group of focusable items using arrow keys while maintaining a single tab stop.
Installation
Components
RovingFocusGroup
The root component that manages focus state for all items within the group.RovingFocusGroupItem
Represents a focusable item within the group.Props
RovingFocusGroup
'horizontal' | 'vertical' | 'both'
The orientation of the group, which determines which arrow keys navigate between items:
horizontal: Left/Right arrowsvertical: Up/Down arrowsboth: All arrow keys
'ltr' | 'rtl'
The reading direction. Affects horizontal keyboard navigation.
boolean
Whether keyboard navigation should wrap around when reaching the first or last item.Default:
falsestring | null
The controlled tab stop id. Use with
onCurrentTabStopIdChange for controlled mode.string
The default tab stop id for uncontrolled mode.
(tabStopId: string | null) => void
Callback fired when the current tab stop changes.
(event: Event) => void
Event handler called when focus enters the group. Can be prevented.
boolean
Whether to prevent scrolling when focus enters the group.Default:
falseUsage
Basic Example - Horizontal Navigation
Vertical List with Looping
Controlled Focus State
Grid Navigation (2D)
With Disabled Items
RTL Support
Keyboard Interactions
Moves focus to the current tab stop (or first item if none is set).
vertical orientation
Moves focus to the next item.
vertical orientation
Moves focus to the previous item.
horizontal orientation
Moves focus to the next item (in LTR) or previous item (in RTL).
horizontal orientation
Moves focus to the previous item (in LTR) or next item (in RTL).
Moves focus to the first item.
Moves focus to the last item.
Accessibility
The roving tabindex pattern:- Maintains only one tab stop in the group
- Uses arrow keys for navigation within the group
- Follows WAI-ARIA best practices
- Supports RTL languages
- Respects disabled/non-focusable items
Notes
Only one item in the group has
tabIndex={0} at a time. All other items have tabIndex={-1}. This ensures a single tab stop while allowing full keyboard navigation with arrow keys.The component automatically handles focus management, including updating tab indices, focusing items, and managing keyboard navigation based on orientation and direction.
Items marked with
focusable={false} are skipped during keyboard navigation but remain in the DOM.