Mendalami aksesibilitas dari episode 3: peran ARIA dan kapan memakainya, navigasi keyboard & fokus, kontras warna, serta pengujian aksesibilitas otomatis dengan axe dan Playwright — lewat audit menyeluruh TokoKita

Di episode 3 kita menyentuh dasar aksesibilitas (WCAG/POUR). Episode 15 mendalaminya secara sistematis. Di 2026 aksesibilitas bukan lagi "nice to have": peraturan seperti EU Accessibility Act menjadikannya syarat hukum, dan pengguna dengan disabilitas adalah pengguna nyata yang menguji produk kalian setiap hari.
Pendekatan yang akan kita pakai: built-in semantics first — gunakan elemen HTML yang benar sejak awal (sudah dipelajari di episode 3), tambah ARIA hanya untuk mengisi celah yang benar-benar ada, lalu verifikasi dengan alat otomatis dan pengecekan manual keyboard.
ARIA (Accessible Rich Internet Applications) adalah atribut yang menambahkan informasi semantik untuk teknologi bantu. Aturan pertamanya: jangan memakai ARIA bila elemen HTML sudah menyediakan semantiknya.
<!-- ✅ BENAR: button asli, semantik gratis -->
<button>Beli sekarang</button>
<!-- ❌ SALAH: div dijadikan tombol, perlu ARIA + keyboard manual -->
<div role="button" tabindex="0" onclick="buy()">Beli sekarang</div>Kapan ARIA memang dibutuhkan:
<!-- Label untuk elemen yang tidak punya label visual -->
<button aria-label="Tutup dialog">×</button>
<!-- Status yang berubah tanpa focus -->
<div role="status" aria-live="polite">Produk ditambahkan ke keranjang</div>
<!-- State yang tidak tersedia di HTML -->
<button aria-expanded="false" aria-controls="menu">Menu</button>aria-live="polite" memberi tahu screen reader untuk mengumumkan perubahan (seperti "produk ditambahkan") meski pengguna sedang membaca di tempat lain.
Warning
ARIA tidak mengubah perilaku — ia hanya mengubah informasi yang disampaikan. <div role="button"> tetap tidak bisa ditekan Enter tanpa JavaScript tambahan. Urutan yang benar: HTML semantik dulu, ARIA untuk mengisi celah, jangan ARIA untuk "memperbaiki" struktur yang salah.
Semua interaksi harus bisa dioperasikan keyboard saja:
import { useEffect, useRef } from "react";
export function Dialog({ onClose }: { onClose: () => void }) {
const closeBtn = useRef<HTMLButtonElement>(null);
useEffect(() => {
closeBtn.current?.focus();
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [onClose]);
return (
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Keranjang</h2>
<button ref={closeBtn} onClick={onClose}>Tutup</button>
</div>
);
}Prinsip "nothing is mouse-only": jika sebuah fitur hanya bisa dibuka dengan hover atau drag, fitur itu tidak accessible.
Kontras teks terhadap latar harus memenuhi WCAG:
Elements → pilih teks → klik ikon warna → lihat kontrasJangan pernah menyampaikan informasi hanya dengan warna (misal: "yang merah berarti salah") — tambahkan ikon atau teks.
Alat otomatis menangkap 30-50% masalah — penting sebagai jaring awal, bukan pengganti pengujian manual.
# Install ekstensi axe DevTools, lalu:
# Klik "Scan all of my page" pada halaman TokoKitaDi dalam test, integrasikan axe lewat Playwright:
import { test, expect } from "@playwright/test";
test("katalog tanpa masalah aksesibilitas otomatis", async ({ page }) => {
await page.goto("/products");
const results = await page.evaluate(() =>
window.axe.run ? window.axe.run(document) : null
);
// alternatif praktis: gunakan plugin @axe-core/playwright
});import { render } from "@testing-library/react";
import { axe } from "jest-axe";
it("tidak punya pelanggaran aksesibilitas", async () => {
const { container } = render(<ProductCard product={product} />);
expect(await axe(container)).toHaveNoViolations();
});Checklist audit menyeluruh:
| Area | Alat | Frekuensi |
|---|---|---|
| Static analysis | axe / Lighthouse | Setiap build (CI) |
| Component test | jest-axe | Setiap komponen baru |
| E2E keyboard | Playwright | Alur kritis |
| Uji manual | Pengguna nyata + screen reader | Sebelum rilis |
Tip
Kembangkan "refleks aksesibilitas": setiap kali menulis komponen interaktif, tanya — "apakah ini bisa dioperasikan keyboard? apakah screen reader mendapatkan informasi yang sama?" Refleks ini lebih berharga daripada menghafal daftar teknik.
Inti yang harus dibawa pulang:
aria-label, aria-live, aria-expanded).Di episode 16 selanjutnya kita menghidupkan antarmuka: animasi & interaction — CSS animations, Web Animations API, dan micro-interactions yang membuat TokoKita terasa hidup tanpa mengorbankan performa. Sampai jumpa di episode 16!