vue-a11y-directives

A comprehensive set of Vue 3 directives for building accessible web applications with WCAG compliance
20,510
Install
npm install vue-a11y-directives
Latest Version:1.5.1
Vue:3
License:MIT
Last Updated:Oct 22, 2026
Links: npm
Maintainer: shkelqimemerllahu

Vue A11y Directives

A comprehensive collection of Vue 3 directives for building accessible web applications with WCAG compliance.

🚀 Features

  • 9 Powerful Directives for complete accessibility control
  • Zero Dependencies - Lightweight and performant
  • TypeScript Support - Full type definitions included
  • WCAG Compliant - Follow web accessibility standards
  • Easy to Use - Simple directive-based API
  • Well Documented - Comprehensive documentation and examples

📦 Installation

npm install vue-a11y-directives

🎯 Quick Start

import { createApp } from 'vue'
import App from './App.vue'
import { installA11yDirectives } from 'vue-a11y-directives'

const app = createApp(App)

// Install all directives globally
installA11yDirectives(app)

app.mount('#app')

Or import individual directives:

import { focusDirective, keyboardDirective, ariaDirective } from 'vue-a11y-directives'

export default {
  directives: {
    'a11y-focus': focusDirective,
    'a11y-keyboard': keyboardDirective,
    'a11y-aria': ariaDirective
  }
}

📚 Available Directives

1. v-a11y-focus

Auto-focus elements with conditional logic.

<input v-a11y-focus />
<input v-a11y-focus="200" />  <!-- with 200ms delay -->

2. v-a11y-keyboard

Enhanced keyboard navigation support.

<div v-a11y-keyboard="{ 
  arrowDown: () => next(), 
  arrowUp: () => prev(),
  enter: () => select()
}">

3. v-a11y-aria

Dynamic ARIA attributes management.

<button v-a11y-aria="{ 
  label: 'Close dialog',
  expanded: isOpen,
  controls: 'menu-id'
}">

4. v-a11y-announce

Screen reader announcements.

<div v-a11y-announce="statusMessage"></div>

5. v-a11y-trap-focus

Trap focus within modals/dialogs with Escape key support.

<div v-a11y-trap-focus="{ onEscape: closeModal, autoFocus: false }">
  <!-- Focus stays within this container -->
</div>

6. v-a11y-focus-return

Automatically return focus to trigger element when popups/modals close.

<button 
  v-a11y-focus-return="isPopupOpen"
  @click="isPopupOpen = true"
>
  Open Popup
</button>

<div v-if="isPopupOpen">
  <button @click="isPopupOpen = false">Close</button>
  <!-- When closed, focus returns to "Open Popup" button -->
</div>

Features:

  • ✅ Automatic focus management - no manual handlers needed
  • ✅ Works with Vue component refs ($el pattern)
  • ✅ Configurable delay for smooth transitions
  • ✅ Works with $emit events

Usage patterns:

<!-- Simple boolean -->
<button v-a11y-focus-return="showModal">Open Modal</button>

<!-- Custom delay -->
<button v-a11y-focus-return="{ open: showModal, delay: 200 }">
  Open Modal (200ms delay)
</button>

<!-- Immediate (no delay) -->
<button v-a11y-focus-return.immediate="showDropdown">
  Open Dropdown
</button>

<!-- Works with $emit -->
<button 
  v-a11y-focus-return="showModal"
  @click="showModal = true"
>
  Open
</button>
<ModalComponent 
  v-if="showModal"
  @close="showModal = false"  <!-- Focus returns on $emit -->
/>

7. v-a11y-skip-link

Skip navigation links for keyboard users.

<a v-a11y-skip-link href="#main-content">Skip to main content</a>

8. v-a11y-skip

Skip elements from keyboard navigation.

<!-- Always skip -->
<div v-a11y-skip>Hidden content</div>

<!-- Conditional skip -->
<button v-a11y-skip="item.disabled">Button</button>

<!-- With visual indication -->
<div v-a11y-skip.visual="item.inactive">Grayed out</div>

<!-- Block all interactions -->
<div v-a11y-skip.noInteraction="isProcessing">Processing...</div>

9. v-a11y-date-picker

Enhance date picker accessibility with auto-focus and keyboard navigation.

Important: Apply directive to a wrapper div, not directly on the component.

<template>
  <div v-a11y-date-picker style="position: relative">
    <el-date-picker 
      v-model="date" 
      :teleported="false"
      placeholder="Select date"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue';
const date = ref('');
</script>

Features:

  • ✅ Auto-focuses calendar when opened
  • ✅ Arrow keys navigate dates without auto-selecting
  • ✅ Enter/Space to select focused date
  • ✅ Works with Element Plus, Vuetify, Ant Design Vue, PrimeVue

More Examples:

<!-- Element Plus -->
<div v-a11y-date-picker style="position: relative">
  <el-date-picker v-model="date" :teleported="false" />
</div>

<!-- Vuetify -->
<div v-a11y-date-picker style="position: relative">
  <v-date-picker v-model="date" />
</div>

<!-- Ant Design Vue -->
<div v-a11y-date-picker style="position: relative">
  <a-date-picker v-model:value="date" />
</div>

<!-- PrimeVue -->
<div v-a11y-date-picker style="position: relative">
  <Calendar v-model="date" />
</div>

🎨 Real-World Examples

Accessible Navigation Menu

<template>
  <nav>
    <div v-a11y-announce="announcement"></div>
    <ul v-a11y-keyboard="keyboardHandlers" tabindex="0">
      <li v-for="item in menuItems" :key="item.id">
        <button 
          v-a11y-aria="{ 
            expanded: item.isOpen,
            controls: `menu-${item.id}`
          }"
          @click="toggle(item)"
        >
          {{ item.label }}
        </button>
      </li>
    </ul>
  </nav>
</template>

<script>
export default {
  data() {
    return {
      announcement: '',
      menuItems: ['Home', 'Products', 'About', 'Contact'],
      currentIndex: 0
    }
  },
  computed: {
    keyboardHandlers() {
      return {
        arrowDown: () => this.navigateNext(),
        arrowUp: () => this.navigatePrev(),
        enter: () => this.selectItem()
      }
    }
  },
  methods: {
    navigateNext() {
      this.currentIndex = (this.currentIndex + 1) % this.menuItems.length;
    },
    navigatePrev() {
      this.currentIndex = this.currentIndex === 0 
        ? this.menuItems.length - 1 
        : this.currentIndex - 1;
    },
    selectItem() {
      console.log('Selected:', this.menuItems[this.currentIndex]);
    }
  }
}
</script>

Accessible Modal Dialog

<template>
  <div>
    <button 
      v-a11y-focus-return="isOpen"
      @click="isOpen = true"
    >
      Open Modal
    </button>
    
    <div v-if="isOpen" v-a11y-trap-focus class="modal">
      <div v-a11y-announce="modalAnnouncement"></div>
      <h2 v-a11y-focus>Modal Title</h2>
      <button 
        v-a11y-aria="{ label: 'Close modal' }"
        @click="isOpen = false"
      >
        ×
      </button>
    </div>
  </div>
</template>

Note: When modal closes, focus automatically returns to "Open Modal" button thanks to v-a11y-focus-return!

📖 Documentation

For complete documentation, examples, and interactive demos, visit:

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

MIT © Shkelqim Emerllahu

🌟 Show Your Support

Give a ⭐️ if this project helped you!

📞 Support

Related Packages

@lexical/a11y

Framework-agnostic accessibility helpers (ARIA live regions, focus management, r...

12,617,619 23,971
@focusring/wcagify

WCAG accessibility audit tool — Nuxt layer with report generation, PDF export an...

5,246 1
@focusring/wcagify-reporter

WCAGify's report schemas, scoring and render-only Nuxt layer, for apps that show...

175 1
@accesslint/storybook-addon

Catch accessibility violations in your Storybook stories as you develop

3,861 13
accessibility-menu

Componente de accesibilidad WCAG 2.1 AA para Vue 3, Nuxt 4 y Laravel

1,498 0

Version History

Version Released Vue License
1.5.1 ^3.0.0 MIT
1.5.0 ^3.0.0 MIT
1.4.1 ^3.0.0 MIT
1.4.0 ^3.0.0 MIT
1.2.9 ^3.0.0 MIT