FocusScope is a component that manages focus containment and focus trapping. It’s commonly used in modal dialogs, popovers, and other overlay components to ensure keyboard focus remains within a specific area.
Installation
Component
FocusScope
Props
When
true, tabbing from the last focusable element will focus the first element, and shift+tab from the first element will focus the last. Creates a circular focus loop.Default: falseWhen
true, focus cannot escape the scope via keyboard, pointer, or programmatic focus. This creates a “focus trap” essential for modal dialogs.Default: falseEvent handler called when the component mounts and attempts to auto-focus. Call
event.preventDefault() to prevent the default auto-focus behavior.Event handler called when the component unmounts and attempts to restore focus. Call
event.preventDefault() to prevent restoring focus to the previously focused element.Usage
Basic Modal Dialog
Focus Loop without Trapping
Prevent Auto-focus
Prevent Focus Restore
Nested Focus Scopes
Custom Focus Priority
Form with Focus Management
Behavior
Auto-focus on Mount
By default,FocusScope will:
- Remember the currently focused element
- Focus the first focusable element inside the scope
- Can be prevented with
onMountAutoFocus
Auto-focus on Unmount
By default,FocusScope will:
- Restore focus to the element that was focused before mounting
- Can be prevented with
onUnmountAutoFocus
Focus Trapping
Whentrapped={true}:
- Tab and Shift+Tab are contained within the scope
- Clicking outside cannot move focus out
- Programmatic focus changes to elements outside are prevented
Focus Looping
Whenloop={true}:
- Tab from the last element focuses the first element
- Shift+Tab from the first element focuses the last element
- Works independently of trapping
Accessibility
Focus trapping is essential for modal dialogs to meet WCAG 2.1 success criterion 2.4.3 (Focus Order). It ensures keyboard users can navigate the modal without accidentally leaving it.
Always provide a clear way to dismiss focus-trapped components (like a close button or Escape key handler) to prevent keyboard users from getting stuck.
Notes
FocusScope works by listening to focus events and programmatically managing focus when needed. It respects native browser behavior while adding focus containment.The component uses
focusScope.pause() and focusScope.resume() internally to temporarily disable focus trapping when needed. This is useful for nested focus scopes.Focus guards (from
@radix-ui/react-focus-guards) may be needed alongside FocusScope to ensure focus events are properly captured in all scenarios.