Vue Focus Trap Component

4.1.0 · active · verified Tue Apr 21

focus-trap-vue is a Vue component designed to enhance web accessibility by programmatically trapping keyboard focus within a specified DOM element. This is crucial for UI patterns like modals, dialogs, and sidebars, preventing users of assistive technologies from accidentally tabbing out of the active context. The current stable version is 4.1.0, last published in August 2025, with regular patch and minor releases, indicating active maintenance and a stable API. It acts as a Vue-specific wrapper around the robust `focus-trap` library, inheriting its extensive focus management capabilities. Key differentiators include its seamless integration into Vue applications, support for both Vue 2 (via `@legacy` package) and Vue 3, and flexible control mechanisms via `active` prop, `v-model:active`, or direct method calls, while enforcing best practices for accessibility by leveraging its underlying peer dependency.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates a basic focus trap using `v-model:active` to control visibility and setting `initialFocus` to an input field within a modal-like cookie consent dialog for improved accessibility.

import { createApp, ref } from 'vue';
import { FocusTrap } from 'focus-trap-vue';

const app = createApp({
  components: {
    FocusTrap,
  },
  setup() {
    const isActive = ref(false);
    const nameInput = ref<HTMLInputElement | null>(null);

    return {
      isActive,
      nameInput,
      acceptCookies: () => {
        alert('Cookies accepted!');
        isActive.value = false;
      },
    };
  },
  template: `
    <div>
      <button @click="isActive = true">Open Cookie Consent</button>

      <focus-trap v-model:active="isActive" :initial-focus="() => nameInput.value">
        <div v-if="isActive" style="border: 1px solid #ccc; padding: 20px; background: #f9f9f9; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1000; width: 300px; text-align: center;">
          <p>Do you accept our use of cookies?</p>
          <label>Your Name: <input ref="nameInput" type="text" /></label>
          <div style="margin-top: 15px;">
            <button @click="acceptCookies" style="margin-right: 10px;">Yes, I accept</button>
            <button @click="isActive = false">No, thank you</button>
          </div>
        </div>
      </focus-trap>

      <p style="margin-top: 200px;">Content behind the modal.</p>
      <button>Another button</button>
    </div>
  `,
});

app.mount('#app');

view raw JSON →