Episode ini membahas accessibility dan pengalaman pengguna di Nuxt: dukungan ARIA, navigasi keyboard dan manajemen fokus, HTML semantik dengan komponen yang mudah diakses, responsive design, serta dasar internationalization dengan @nuxtjs/i18n.

Aplikasi yang baik bisa dipakai semua orang — termasuk mereka yang memakai screen reader, bernavigasi hanya dengan keyboard, atau berada di perangkat dengan layar kecil. Episode 17 membahas accessibility dan UX di Nuxt.
Accessibility bukan fitur bonus; dia adalah bagian dari kualitas. Banyak praktik aksesibilitas ternyata memperbaiki UX semua orang: label yang jelas membantu semua orang, urutan fokus yang logis membuat navigasi lebih cepat, dan semantic HTML meningkatkan SEO sekaligus.
ARIA memberikan informasi tambahan ke screen reader. Aturan emasnya: pakai elemen HTML semantik dulu, ARIA hanya untuk melengkapi:
<template>
<div
v-if="terbuka"
role="dialog"
aria-modal="true"
aria-labelledby="judul-dialog"
>
<h2 id="judul-dialog">Pilih Pengiriman</h2>
<button @click="terbuka = false">Tutup</button>
</div>
</template>role="dialog" dan aria-modal="true" memberi tahu screen reader bahwa ini dialog yang menahan interaksi halaman. aria-labelledby menghubungkan dialog ke judulnya.
Semua interaksi penting harus bisa dilakukan dengan keyboard. Fokus harus berpindah secara logis — dan saat dialog tertutup, fokus harus kembali ke elemen yang membukanya:
function tutupDialog() {
terbuka.value = false
nextTick(() => {
tombolBuka.value?.focus()
})
}nextTick(() => tombolBuka.value?.focus()) mengembalikan fokus ke tombol pembuka setelah dialog tertutup. Pola ini penting untuk pengguna keyboard dan screen reader.
Gunakan elemen sesuai maknanya — header, nav, main, section, dan footer — sehingga screen reader bisa menavigasi struktur halaman. Satu aturan yang sering dilanggar: tombol harus <button>, bukan <div> yang diberi event klik.
<template>
<button type="button" @click="tambahKeranjang">
Tambah ke Keranjang
</button>
</template><button> gratis mendapatkan dukungan keyboard: bisa difokuskan dan diaktifkan dengan Enter atau Space. Menggantinya dengan div berarti kalian harus membangun ulang perilaku itu secara manual.
Hubungkan setiap label ke input dengan atribut id, dan gunakan aria-describedby untuk menautkan pesan error:
<template>
<label for="email">Email</label>
<input id="email" v-model="email" type="email" aria-describedby="err-email" />
<p id="err-email" role="alert" v-if="errors.email">
{{ errors.email }}
</p>
</template>aria-describedby membuat screen reader membacakan pesan error yang terhubung dengan input. Kombinasikan dengan pola episode 10 untuk form yang lengkap.
Rancang untuk layar kecil lebih dulu, lalu tingkatkan untuk layar besar. Tailwind atau CSS media query keduanya mendukung pola ini:
<template>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<KartuProduk v-for="item in produk" :key="item.id" v-bind="item" />
</div>
</template>grid-cols-1 md:grid-cols-3 menampilkan satu kolom di ponsel dan tiga kolom di layar sedang ke atas. Pastikan target sentuh cukup besar — minimal 44 piksel — dan teks tidak terlalu kecil untuk dibaca.
Layout adaptif menyesuaikan konten, bukan hanya ukuran. Contohnya menyembunyikan kolom yang tidak esensial di layar kecil, atau menyajikan versi ringkas. Ini keputusan desain yang sebaiknya diuji dengan pengguna nyata.
Untuk dukungan multi bahasa, gunakan module i18n resmi:
npm install @nuxtjs/i18nexport default defineNuxtConfig({
modules: ["@nuxtjs/i18n"],
i18n: {
locales: [{ code: "id", name: "Indonesia" }, { code: "en", name: "English" }],
defaultLocale: "id",
},
})Simpan terjemahan di folder i18n/locales lalu pakai fungsi t:
const { t } = useI18n()
const judul = t("produk.tambahKeKeranjang")t("produk.tambahKeKeranjang") mengambil terjemahan sesuai locale aktif. Untuk SEO, i18n juga menangani URL ber-locale seperti /en/produk — mendukung inklusivitas bahasa sekaligus peringkat pencarian.
Episode 17 menjadikan aplikasi kalian ramah untuk semua pengguna: ARIA yang dipakai dengan benar, navigasi keyboard dengan manajemen fokus, HTML semantik sebagai fondasi, responsive dan adaptive layouts untuk semua ukuran layar, serta dasar internationalization dengan module i18n.
Inti yang harus dibawa pulang:
<button>, bukan div yang diberi event klik.id dan aria-describedby.Di episode 18 selanjutnya kita akan membahas architecture dan modularization — struktur project berbasis fitur, pengembangan module dan utility composables, separation of concerns antara UI, data, dan logika, serta cara menjaga codebase Nuxt tetap skalabel.