Trap focus
The TrapFocus
component prevents the user's focus from escaping its children components.
TrapFocus
is a utility component that is useful when implementing an overlay such as a modal dialog, which should block all interactions outside of it while open.
TrapFocus
import TrapFocus from '@mui/base/TrapFocus';
Basic trap focus
The following demo shows a Button
that opens a Box
component nested inside of a TrapFocus
. As long as the Box
is open, the user's keyboard cannot interact with the rest of the app:
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
{open && (
<TrapFocus open>
<Box tabIndex={-1} sx={{ mt: 1, p: 1 }}>
<label>
First name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</Box>
</TrapFocus>
)}
Disable enforced focus
By default, clicks outside of the TrapFocus
component are blocked.
You can disable this behavior with the disableEnforceFocus
prop:
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
{open && (
<TrapFocus disableEnforceFocus open>
<Box tabIndex={-1} sx={{ mt: 1, p: 1 }}>
<label>
First name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</Box>
</TrapFocus>
)}
Lazy activation
By default, the TrapFocus
component automatically moves the focus to the first of its children when the open
prop is present.
You can disable this behavior and make it lazy with the disableAutoFocus
prop.
When auto focus is disabled—as in the demo below—the component only traps the focus once the user moves it there:
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
{open && (
<TrapFocus open disableAutoFocus>
<Box tabIndex={-1} sx={{ mt: 1, p: 1 }}>
<label>
First name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</Box>
</TrapFocus>
)}
Escape the focus loop
The following demo uses the Portal
component to render a subset of the TrapFocus
children into a new "subtree" outside of the current DOM hierarchy.
This way, they are no longer part of the focus loop.