FocusScope
Manage keyboard focus trapping and roving navigation accessibly
Components for managing keyboard focus: FocusScope for trapping and containing focus within modals and dialogs, and RovingFocusGroup for arrow-key roving tabindex navigation across composite widgets.
These are web-only components. On native they render their children with no keyboard navigation management.
Features
Focus trapping for modal dialogs and overlays
Composite-widget arrow navigation with one tab stop
Autofocus on mount, focus restoration on unmount
Focus looping between first and last tabbable elements
Focus-inert content with noFocus
Animation reflow prevention with focusOnIdle
Installation
FocusScope and RovingFocusGroup ship in their own packages:
yarn
npm
bun
pnpm
Focus trapping (FocusScope)
Wrap any content that needs focus containment or trapping:
In v3, FocusScope renders a display: contents wrapper so it does not add an extra layout box around its children.
Trapped focus
Use trapped to prevent focus from escaping the scope (ideal for modals, dialogs, and sheets):
Zero focus mode
Use noFocus to disallow focus entirely while the scope is active: focus can land neither inside nor outside the scope. Any element that receives focus is immediately blurred, so document.activeElement settles on document.body. This takes precedence over trapped and auto-focus behavior:
Focus looping
Enable loop to cycle focus between first and last elements:
Animation-friendly focusing
Use focusOnIdle to prevent reflows during animations:
Advanced control with FocusScopeController
Use the controller pattern for managing focus from parent components:
FocusScope props
Props
enabled
boolean
Default:
trueWhether focus management is enabled
loop
boolean
Default:
falseWhen true, tabbing from last item will focus first tabbable and shift+tab from first item will focus last tabbable
trapped
boolean
Default:
falseWhen true, focus cannot escape the focus scope via keyboard, pointer, or programmatic focus
noFocus
boolean
Default:
falseZero focus mode: while active, focus is allowed neither inside nor outside the scope. Anything that receives focus is immediately blurred. Takes precedence over trapped and auto-focus. Web only
focusOnIdle
boolean | number | { min?: number; max?: number }
Default:
trueWhen true, waits for idle before focusing using requestIdleCallback. When a number, waits that many ms. Object sets a lower and upper bound. Helps to prevent reflows during animations, as focusing inputs easily blocks main thread.
onMountAutoFocus
(event: Event) => void
Event handler called when auto-focusing on mount. Can be prevented
onUnmountAutoFocus
(event: Event) => void
Event handler called when auto-focusing on unmount. Can be prevented
forceUnmount
boolean
Default:
falseIf unmount is animated, you want to force re-focus at start of animation not after
children
React.ReactNode
Content to apply focus management to
FocusScopeController props
Provides context-based control over FocusScope behavior:
Props
enabled
boolean
Override enabled state for all child FocusScope components
loop
boolean
Override loop state for all child FocusScope components
trapped
boolean
Override trapped state for all child FocusScope components
noFocus
boolean
Override noFocus (zero focus mode) for all child FocusScope components
focusOnIdle
boolean | number
Override focusOnIdle behavior for all child FocusScope components
onMountAutoFocus
(event: Event) => void
Override onMountAutoFocus handler for all child FocusScope components
onUnmountAutoFocus
(event: Event) => void
Override onUnmountAutoFocus handler for all child FocusScope components
forceUnmount
boolean
Override forceUnmount behavior for all child FocusScope components
The FocusScope component automatically inherits props from the nearest FocusScopeController, with controller props taking precedence over direct props.
Roving focus (RovingFocusGroup)
The roving tabindex pattern manages focus across a group of interactive elements (like toolbars, tab lists, or radio groups) so that the entire group acts as a single tab stop. Arrow keys move focus between items within the group, and pressing Tab moves focus out of the group.
Orientation
Set orientation to "horizontal" or "vertical" to control which arrow keys navigate:
Looping navigation
Enable loop to wrap focus from the last item back to the first:
Controlled tab stop
Control which item is the current tab stop via currentTabStopId and onCurrentTabStopIdChange:
Non-focusable items
Give an item a negative tabIndex to make it non-focusable and skip it during keyboard navigation:
RovingFocusGroup props
Props
orientation
"horizontal" | "vertical"
The orientation of the group. Determines which arrow keys are used for navigation (left/right vs up/down).
dir
"ltr" | "rtl"
The reading direction. When set to rtl, left and right arrow keys are reversed.
loop
boolean
Default:
falseWhen true, keyboard navigation will loop from last to first and vice versa.
currentTabStopId
string | null
The controlled id of the current tab stop.
defaultCurrentTabStopId
string
The default id of the current tab stop for uncontrolled usage.
onCurrentTabStopIdChange
(tabStopId: string | null) => void
Callback when the current tab stop changes.
onEntryFocus
(details: RovingFocusEntryDetails) => void
Callback when focus enters the group via keyboard. Call details.cancel() to prevent the default focus behavior.
asChild
boolean
Default:
falseWhen true, renders as a Slot, merging props onto the child element.
RovingFocusGroup.Item props
Props
tabStopId
string
A unique identifier for this item. Auto-generated if not provided.
tabIndex
number
Default:
0Items with a negative tabIndex are skipped during keyboard navigation.
active
boolean
Default:
falseWhether this item is considered active. Active items receive focus priority when the group is entered.
asChild
boolean
Default:
falseWhen true, renders as a Slot, merging props onto the child element.
Keyboard navigation
| Key | Action |
|---|---|
Tab | Move focus into/out of the group |
Arrow Left/Right | Move focus between items (horizontal orientation) |
Arrow Up/Down | Move focus between items (vertical orientation) |
Home / Page Up | Move focus to first item |
End / Page Down | Move focus to last item |
- Key
Tab- Action
- Move focus into/out of the group
- Key
Arrow Left/Right- Action
- Move focus between items (horizontal orientation)
- Key
Arrow Up/Down- Action
- Move focus between items (vertical orientation)
- Key
Home/Page Up- Action
- Move focus to first item
- Key
End/Page Down- Action
- Move focus to last item
Internal usage in Tamagui
FocusScope and RovingFocusGroup power accessibility throughout Tamagui:
- FocusScope handles focus trapping in Dialog, AlertDialog, Sheet, and Popover.
- RovingFocusGroup manages roving arrow-key navigation in Tabs, RadioGroup, and ToggleGroup.
Both components are primarily designed for web platforms. On React Native, they render children directly without web focus management since native platforms manage focus and touch interaction natively.