All guides
Framework guide · Framework

Accessibility for Vue apps.

Vue 3's reactivity and template directives let you ship dynamic UI fast — and often skip semantic HTML in the process. The patterns, plugins, and audit workflows that catch the recurring failures.

Recurring issues

What goes wrong in Vue projects.

01

v-on:click on <div> instead of <button>

Vue's `@click` directive works on any element, which makes it easy to drop click handlers on `<div>` or `<span>` and ship something that mouse users can use but keyboard users cannot. Use `<button>` and style it down.

02

v-if dropping content without aria-live

Toggling validation messages, toasts, or notifications with `v-if` is invisible to screen readers unless the parent is an aria-live region. Wrap with `role="status"` or `role="alert"`.

03

Custom modal components without focus trap

Hand-rolled `<Teleport to="body">` modals usually skip focus trapping. Use Vue's `focus-trap-vue` or Headless UI Vue's `Dialog` for correct behavior.

04

Forms without proper label binding

Vue components that wrap `<input>` often break the label-input relationship. Pass `id` from props and bind to both `<label for={id}>` and `<input :id="id">`. Use `useId()` from Vueuse for unique IDs.

05

v-for without :key on accessible widgets

Missing or non-unique keys cause Vue to reuse DOM nodes incorrectly when lists update. This can move focus unexpectedly and re-announce content. Always provide a stable, unique `:key`.

06

Transition components masking aria-live updates

Vue's `<Transition>` and `<TransitionGroup>` can delay or mask DOM changes from screen readers. For aria-live regions, prefer immediate visibility over animated entry.

Recommended tooling

The Vue accessibility stack we recommend.

eslint-plugin-vuejs-accessibility

npm i eslint-plugin-vuejs-accessibility

Vue-specific port of jsx-a11y. Catches missing alt, invalid roles, click without keyboard handler, in `.vue` templates at lint time.

@axe-core/vue

npm i @axe-core/vue

Plugin that runs axe-core against the live Vue app during development. Console logs WCAG violations. Strip in production.

Headless UI Vue

npm i @headlessui/vue

Accessible primitives: Dialog, Menu, Listbox, Combobox, Switch. Same family as the React version, Tailwind-friendly.

Radix Vue

npm i radix-vue

Vue port of Radix UI primitives. Unstyled, accessible, full ARIA coverage. Use for complex widgets where Headless UI is too thin.

focus-trap-vue

npm i focus-trap-vue

Wrapper around focus-trap. Drop-in component to trap focus inside a custom modal or panel.

Audit workflow

Step-by-step for a Vue accessibility audit.

  1. 1

    Install eslint-plugin-vuejs-accessibility

    Add to your eslint config: `extends: ["plugin:vuejs-accessibility/recommended"]`. Run on existing code; expect 10-100 violations on the first pass.

  2. 2

    Add @axe-core/vue in main.ts (dev only)

    Gate the plugin install on `import.meta.env.DEV`. Watch the browser console for live a11y reports.

  3. 3

    Audit your design system templates

    Most Vue accessibility debt clusters in shared components (Modal, Dropdown, FormField). Audit those first — fixes cascade to every consumer.

  4. 4

    Add AccessProof to CI

    External audit of deployed URLs. Block PRs that introduce regressions. Works for any Vue framework (Nuxt, Vite SPA, custom).

  5. 5

    Manual screen reader pass

    Use NVDA (Windows) or VoiceOver (macOS) on a representative flow. Tab order, announcement quality, error visibility.

Scan your Vue app

Run a WCAG audit on your Vue site in 42 seconds.

External scan — no JS injected into your app

WCAG 2.2 + Section 508 + EN 301 549 in one pass

Court-ready PDF with element selectors

CI/CD gate — block deploys on regression

Works with Vue on any hosting (Vercel, Netlify, Fly, self-hosted)

Free plan — 1 site, monthly scan

FAQ

Vue-specific questions.

Is Vue 3 more accessible than Vue 2?

They are equivalent in baseline accessibility — both emit standard HTML and depend on what your components render. Vue 3 adds `<Teleport>` (useful for modal portals) and improved TypeScript support (helps catch some bugs at compile time), but the accessibility responsibility is the same.

Does Nuxt have built-in accessibility tooling?

Nuxt does not bundle accessibility tooling by default. It provides good defaults (page title management, automatic head tags) that help with some WCAG criteria, and the broader Vue ecosystem (eslint plugin, vue-axe, Headless UI Vue) integrates cleanly with Nuxt.

How do I handle accessibility in component libraries like Vuetify or PrimeVue?

Both ship many components with reasonable ARIA defaults but specific accessibility quality varies by component. Audit the components you use heavily (data table, dialog, menu) against your own users' assistive tech. Some teams pair a major component library with react-aria-style primitives for the components where the library falls short.

What about Vue 2 / Options API legacy code?

Same WCAG rules apply. The eslint plugin works on both Composition and Options API. Focus management and ARIA attributes are framework-agnostic. The biggest legacy risk is custom-built modals from the Vue 2 era that pre-date the focus-trap libraries — audit those specifically.