DEV Community

Cover image for Accessibility in Vue: Quick Tips for Building Inclusive Apps
Jakub Andrzejewski
Jakub Andrzejewski

Posted on

Accessibility in Vue: Quick Tips for Building Inclusive Apps

Accessibility is not a “nice to have” — it is a fundamental part of building modern web applications.

An accessible application:

  • Reaches more users
  • Improves usability for everyone
  • Reduces legal risks
  • Strengthens brand reputation

When working with Vue, accessibility is largely in your hands. Vue does not limit accessibility — but it also does not automatically solve it for you.

In this article, we’ll go through practical and quick tips for improving accessibility in Vue apps:

  • Keyboard shortcuts & navigation
  • ARIA labels & roles
  • Focus management

Enjoy!

🤔 Why Accessibility Matters in Vue Apps

Modern SPAs introduce challenges that traditional multi-page websites did not have:

  • Dynamic content updates
  • Client-side routing
  • Modal dialogs
  • Complex component trees

Without proper accessibility handling, users relying on:

  • Screen readers
  • Keyboard navigation
  • Assistive technologies

may struggle to use your app.

The good news? Most accessibility improvements require small, intentional changes.

🟢 Keyboard Navigation & Shortcuts

Many users do not use a mouse. They rely entirely on:

  • Tab
  • Shift + Tab
  • Enter
  • Space
  • Arrow keys

Make Elements Focusable

Use semantic HTML whenever possible:

<button @click="submit">
  Submit
</button>
Enter fullscreen mode Exit fullscreen mode

Avoid:

<div @click="submit">
  Submit
</div>
Enter fullscreen mode Exit fullscreen mode

If you must use a non-semantic element, make it keyboard-accessible:

<div
  role="button"
  tabindex="0"
  @click="submit"
  @keydown.enter="submit"
>
  Submit
</div>
Enter fullscreen mode Exit fullscreen mode

Logical Tab Order

Ensure that your DOM structure follows a logical navigation flow.

Avoid:

  • Random tabindex values
  • Skipping interactive elements
  • Hidden focus traps

Use tabindex="0" only when necessary.

Keyboard Shortcuts

Vue makes it easy to listen for keyboard events:

<script setup>
import { onMounted, onBeforeUnmount } from 'vue'

function handleKey(e) {
  if (e.key === 'k' && e.ctrlKey) {
    openSearch()
  }
}

onMounted(() => {
  window.addEventListener('keydown', handleKey)
})

onBeforeUnmount(() => {
  window.removeEventListener('keydown', handleKey)
})
</script>
Enter fullscreen mode Exit fullscreen mode

Best practices:

  • Always document shortcuts
  • Avoid overriding browser defaults
  • Provide alternative UI access

Keyboard shortcuts should enhance usability — not replace accessibility.

🟢 ARIA Labels & Roles

ARIA (Accessible Rich Internet Applications) attributes help screen readers understand UI meaning when semantic HTML is not enough.

aria-label

Useful when visual text is not descriptive:

<button aria-label="Close modal" @click="close"></button>
Enter fullscreen mode Exit fullscreen mode

Without aria-label, a screen reader might only read “button”.

aria-hidden

Hide decorative elements from assistive technologies:

<span aria-hidden="true">🎉</span>
Enter fullscreen mode Exit fullscreen mode

aria-live

For dynamic updates (like notifications):

<div aria-live="polite">
  {{ message }}
</div>
Enter fullscreen mode Exit fullscreen mode

This informs screen readers that content has changed.

Proper Roles

If you create custom components (dropdowns, tabs, modals), use appropriate roles:

<div role="dialog" aria-modal="true">
  <h2>Settings</h2>
</div>
Enter fullscreen mode Exit fullscreen mode

However, remember:

👉 Native HTML elements are always preferred over ARIA when possible.

🟢 Focus Management

Focus management is one of the most overlooked accessibility issues in Vue apps.

Especially when dealing with:

  • Modals
  • Route changes
  • Dynamic content
  • Dropdowns

Managing Focus in Modals

When opening a modal:

  • Move focus into the modal
  • Trap focus inside
  • Return focus when closing

Example:

<script setup>
import { ref, nextTick } from 'vue'

const modalRef = ref(null)

function openModal() {
  isOpen.value = true

  nextTick(() => {
    modalRef.value?.focus()
  })
}
</script>

<template>
  <div
    v-if="isOpen"
    ref="modalRef"
    tabindex="-1"
    role="dialog"
  >
    Modal content
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Focus After Route Changes

In SPAs, screen readers do not automatically detect route changes.

You should move focus to the main heading after navigation.

Example:

<script setup>
import { useRoute } from 'vue-router'
import { watch, nextTick } from 'vue'

const route = useRoute()

watch(() => route.path, async () => {
  await nextTick()
  document.querySelector('h1')?.focus()
})
</script>
Enter fullscreen mode Exit fullscreen mode

And ensure the heading is focusable:

<h1 tabindex="-1">
  Page Title
</h1>
Enter fullscreen mode Exit fullscreen mode

Avoid Focus Traps

Common mistakes:

  • Removing elements without restoring focus
  • Dynamically hiding focused elements
  • Infinite focus loops

Always test:

  • Tab navigation
  • Shift + Tab navigation
  • Screen reader behavior

🧪 Quick Accessibility Checklist for Vue

Before shipping your feature:

  • ✅ Can I navigate everything using only keyboard?
  • ✅ Are all buttons real <button> elements?
  • ✅ Do interactive icons have aria-label?
  • ✅ Does focus move correctly after modals and navigation?
  • ✅ Are dynamic updates announced properly?

These small checks dramatically improve usability.

📖 Learn more

If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:

Vue School Link

It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉

🧪 Advance skills

A certification boosts your skills, builds credibility, and opens doors to new opportunities. Whether you're advancing your career or switching paths, it's a smart step toward success.

Check out Certificates.dev by clicking this link or by clicking the image below:

Certificates.dev Link

Invest in yourself—get certified in Vue.js, JavaScript, Nuxt, Angular, React, and more!

✅ Summary

Accessibility in Vue does not require massive architectural changes — it requires intentional implementation.

Small improvements make your app:

  • More inclusive
  • More professional
  • More compliant
  • More usable for everyone

Take care!
And happy coding as always 🖥️

Top comments (0)