Learn Vue - Accessibility & UX
Series/Learn Vue/Episode 17
Episode 17 of 24

Learn Vue - Accessibility & UX

This episode covers inclusive user experience: the role of ARIA and accessible components, keyboard navigation and focus management, semantic HTML, mobile-first responsive design, and the basics of internationalization with vue-i18n.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

A good application is used by everyone: those using a mouse, keyboard, or screen reader; those with wide or narrow screens; those speaking Indonesian or another language. Accessibility and UX aren't a separate layer — they're a way of thinking when building every component.

Episode 17 covers ARIA roles, keyboard navigation and focus management, semantic HTML for components that assistive technology can understand, mobile-first responsive design, and the basics of internationalization with vue-i18n.

ARIA Roles and Accessible Components

When ARIA Is Needed

ARIA tells assistive technology about the role of elements that HTML doesn't imply. Add it only when native elements aren't enough, such as with custom-built modals, toasts, or tabs.

JSToast dengan aria-live
<script setup>
import { ref } from "vue";
const pesan = ref("");
const tampil = ref(false);
 
function notif(teks) {
  pesan.value = teks;
  tampil.value = true;
}
</script>
 
<template>
  <div v-if="tampil" role="status" aria-live="polite">
    {{ pesan }}
  </div>
</template>

role="status" and aria-live="polite" make screen readers announce the change without interrupting the user's focus. Toasts built with this pattern are no longer invisible to assistive technology.

Keyboard Accessibility and Focus Management

Every important interaction must be doable with the keyboard:

JSNavigasi keyboard
<script setup>
const items = ["Beranda", "Profil", "Pengaturan"];
 
function pilih(index) {
  console.log("dipilih:", items[index]);
}
</script>
 
<template>
  <div role="tablist">
    <button
      v-for="(item, index) in items"
      :key="item"
      role="tab"
      tabindex="0"
      @keydown.enter="pilih(index)"
      @keydown.space="pilih(index)"
    >
      {{ item }}
    </button>
  </div>
</template>

@keydown.enter and @keydown.space handle activation with the keyboard, and tabindex="0" makes the buttons focusable. Managed focus lets the application be navigated without a mouse.

Focus Management on Modals

When a modal opens, focus must move into it; when it closes, focus returns to the original element:

JSFokus ke modal
import { ref, nextTick } from "vue";
 
const modalEl = ref(null);
 
async function bukaModal() {
  terbuka.value = true;
  await nextTick();
  modalEl.value.querySelector("input").focus();
}

nextTick waits for the DOM to update, then querySelector("input").focus() moves focus inside the modal. This technique keeps keyboard users from getting lost behind the overlay.

Semantic HTML for Components

Use HTML elements according to their meaning: header, nav, main, aside, and footer for page structure; button for actions; a for navigation. Action buttons shouldn't be <div @click>, because they can't be focused and aren't announced as buttons by screen readers.

HTMLStruktur semantik
<template>
  <header>
    <nav>Menu utama</nav>
  </header>
  <main>
    <h1>Beranda</h1>
    <section>Konten utama</section>
  </main>
  <footer>Kredit halaman</footer>
</template>

Semantic structure makes it easy for screen readers to produce a navigation summary, and at no extra cost it helps SEO and code maintenance.

Mobile-first Responsive Design

Content-based Breakpoints

Start from a small screen size, then scale up for larger screens:

CSSCSS mobile-first
.kartu {
  display: block;
}
 
@media (min-width: 768px) {
  .kartu {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 768px) only adds rules for wider screens. The mobile-first approach forces you to prioritize the most important content.

Internationalization with vue-i18n

Install and Setup

vue-i18n is the official i18n solution for Vue:

Install vue-i18n
npm install vue-i18n@9
JSSetup vue-i18n
import { createI18n } from "vue-i18n";
 
const i18n = createI18n({
  locale: "id",
  fallbackLocale: "en",
  messages: {
    id: { sambutan: "Selamat datang" },
    en: { sambutan: "Welcome" },
  },
});

createI18n accepts the active locale and a fallback. Translations are stored as a messages object per language.

Info

The best accessibility is tested with real users: try navigating the application with only the keyboard and check it with a screen reader. Automated tools find part of the issues; users find the rest.

Summary

Episode 17 made your application inclusive: proper ARIA for custom components, keyboard navigation and focus management, semantic HTML that assistive technology understands, mobile-first responsive design, and internationalization with vue-i18n.

Key takeaways:

  • Add ARIA only when native elements aren't enough.
  • All important actions are accessible with the keyboard.
  • Manage focus on modals and dynamic content.
  • Semantic structure helps screen readers and SEO.
  • Start small, then scale up with media queries.
  • vue-i18n separates text from application logic.

In the next episode 18, we'll cover architecture and design patterns — large-scale application architecture, feature-based folder structure, reusable component libraries and design systems, and separating logic, UI, and services.

Learn Vue - Accessibility & UX | Learn Vue