The focusTrap
behavior and useFocusTrap
hook are used prevent focus from leaving a particular element. This is useful for implementing modal dialogs: only the content within the dialog should be interactive, even though the UI underneath may still be visible.
initialFocus
parameter (see API below).TAB
key on the last focusable element within the container will result in the first focusable element within the container receiving focus. Similarly, Shift+TAB
can be used to focus the last element from the first.To see a demo, deploy Storybook and find the useFocusTrap
stories.
function showDialog() {const dialog = document.getElementById('myDialog')if (dialog instanceof HTMLElement) {dialog.style.display = ''return focusTrap(dialog)}}function hideDialog(controller: AbortController) {document.getElementById('myDialog')?.style.display = 'none'controller.abort()}const dialogController = showDialog()// laterif (dialogController) {hideDialog(controller)}
The focusTrap
function takes the following arguments.
Name | Type | Default | Description |
---|---|---|---|
container | HTMLElement | When active, only elements within this container (along with the container itself) can be focused. | |
initialFocus | HTMLElement | Specifies the element which will receive focus when the focus trap is activated. Defaults to the first tabbable element inside the container. | |
signal | AbortSignal? | undefined | Optional abort signal to control the focus trap. If one is not provided, an AbortController will be returned, which can be used to disable the focus trap. |
If the signal
argument is omitted, focusTrap()
will return an AbortController
. This object has an abort()
method, which can be called to disable the focus trap.
When focus trap is activated, it must perform reflow to discover focusable elements. Use caution not to rapidly enable and disable focus traps.
The useFocusTrap
hook is used to achieve focus trapping for React components. The hook returns a ref
that must be applied to the focus trap container. The hook also returns a ref that can be used to indicate the initially-focused element when a focus trap is activated.
The focus trap can be disabled in two ways:
disabled: true
to the settings argument of useFocusTrap
.The useFocusTrap
hook also has an additional setting, restoreFocusOnCleanUp
. If this is set to true, when the hook is either disabled (called with disabled: true
or unmounted), we will attempt to re-focus the element that was focused immediately before the focus trap was enabled.
If you would like to use your own refs, you can pass them into the hook as part of the settings object (see the interface below).
export const FocusTrapExample = () => {const {containerRef} = useFocusTrap()return (<div ref={containerRef as React.RefObject<HTMLDivElement>}><Button>Apple</Button><Button>Banana</Button><Button>Cantaloupe</Button></div>)}
FocusTrapHookSettings
has the following properties:
Name | Type | Default | Description |
---|---|---|---|
containerRef | React.RefObject | undefined | If provided, this will be the ref used to access the focus trap container. Otherwise, this hook will create the ref for you and return it. In both cases, the ref must be provided to the container element's JSX. |
initialFocusRef | React.RefObject | undefined | If provided, this will be the ref used to access the element that should receive initial focus when the focus trap is activated. Otherwise, this hook will create the ref for you and return it. If unused, the first tabbable element inside the container will be focused. |
disabled | boolean | false | If true, the previously-established focus trap for this container will be aborted. |
restoreFocusOnCleanUp | boolean | false | If true, attempt to restore focus to the previously-focused element when the trap is disabled or unmounted. |