Looking for a Vue 3 version? It's over here
Vue component to trap the focus within a DOM element
npm install focus-trap focus-trap-vue
This library exports one single named export FocusTrap
and requires
focus-trap
as a peer
dependency. So you can locally import the component or declare it globally:
import { FocusTrap } from 'focus-trap-vue'
Vue.component('FocusTrap', FocusTrap)
FocusTrap
can be controlled in three different ways:
- by using the
active
Boolean prop - by using
v-model
(uses theactive
prop) - by calling the
activate
/deactivate
method on the component
The recommended approach is using v-model
and it should contain one single child:
<focus-trap v-model="isActive">
<modal-dialog tabindex="-1">
<p>
Do you accept the cookies?
</p>
<button @click="acceptCookies">Yes</button>
<button @click="isActive = false">No</button>
</modal-dialog>
</focus-trap>
When isActive
becomes true
, it activates the focus trap. By default it sets
the focus to its child, so make sure the element is a focusable element. If it's
not you wil need to give it the tabindex="-1"
attribute. You can also
customize the initial element focused. This element should be an element that
the user can interact with. For example, an input. It's a good practice to
always focus an interactable element instead of the modal container:
<focus-trap v-model="isActive" :initial-focus="() => $refs.nameInput">
<modal-dialog>
<p>
What name do you want to use?
</p>
<form @submit.prevent="setName">
<label>
New Name
<input ref="nameInput" />
</label>
<button>Change name</button>
</form>
</modal-dialog>
</focus-trap>
FocusTrap
also accepts other props:
escapeDeactivates
:boolean
returnFocusOnDeactivate
:boolean
allowOutsideClick
:boolean | ((e: MouseEvent) => boolean)
clickOutsideDeactivates
:boolean
initialFocus
:string | (() => Element)
Selector or function returning an ElementfallbackFocus
:string | (() => Element)
Selector or function returning an Element
Please, refer to focus-trap documentation to know what they do.
FocusTrap
emits 2 events. They are in-sync with the prop active
activate
: Whenever the trap activatesdeactivate
: Whenever the trap deactivates (note it can also be deactivated by pressing Esc or clicking outside)
FocusTrap
can be used without v-model
. In that case, you will use the
methods and probably need to initialize the trap as deactivated, otherwise,
the focus will start as active:
<button @click="() => $refs.focusTrap.activate()">Show the modal</button>
<focus-trap :active="false" ref="focusTrap">
<modal-dialog>
<p>Hello there!</p>
<button @click="() => $refs.focusTrap.deactivate()">Okay...</button>
</modal-dialog>
</focus-trap>
Note the use of arrow functions, this is necessary because we are accessing
$refs
which are unset on first render.