Aksesibilitas Form & Navigasi — UI/UX

A11y untuk Form dan Navigasi Form dan navigasi adalah area di mana accessibility paling berdampak — ini tempat user berinteraksi aktif dengan website…

Form dan navigasi adalah tempat orang paling banyak berbuat di halaman: memilih, mengetik, menekan, berpindah. Bayangin formulir kertas di meja resepsionis homestay. Tiap kotak punya tulisan tercetak di sampingnya, tiga pilihan jumlah malam dikurung satu bingkai berjudul "Jumlah malam", catatan kesalahan ditulis tepat di samping kotaknya, dan tamu langganan boleh langsung lompat ke bagian yang dia perlu. Di web, tulisan tercetak itu <label>, bingkainya <fieldset>, catatan kesalahannya aria-describedby, dan jalan pintasnya skip link.

🧪 Tebakan cepat: Di halaman pesan Bu Sri, cincin fokus dihapus dengan outline: none supaya "lebih rapi". Pak Hadi memakai keyboard dan menekan Tab 5 kali dari awal halaman. Fokusnya di mana, dan bagaimana dia tahu? Jawabannya ada di bagian "Fokus yang terlihat, urutan yang masuk akal".

Kita kerjakan form pesan Kamar Teras, yang sama dengan Lab di halaman ini. Semua yang disebut "di pohon Chromium" kami baca dari pohon aksesibilitas Chromium 147 untuk tiap kolom, di tiap keadaan Lab.

Label yang tersambung

<label for="wa">Nomor WhatsApp</label>
<input id="wa" name="wa" type="tel" autocomplete="tel" aria-required="true" aria-invalid="true" aria-describedby="wa-help wa-error">
<p id="wa-help" class="help">Contoh: 0812 3456 7890 atau +62 812 3456 7890</p>
<p id="wa-error" class="error" role="alert">Nomor ini 7 digit. Nomor HP diawali 08 dan panjangnya 10 sampai 13 digit.</p>

Di latihan nanti, form-nya punya <input type="text" id="name"> dan <input type="email" id="email"> dengan placeholder saja. Tambahkan <label for="name">Nama</label> dan <label for="email">Email</label>; tiap for harus menunjuk id yang benar-benar ada.

Wajib diisi: required atau aria-required

Tanda bintang merah cuma terlihat mata. Kewajibannya diumumkan lewat atribut di input-nya sendiri, dengan salah satu dari dua cara:

Atribut Di pohon Chromium Browser ikut mengecek?
required required: true ya, kecuali form diberi novalidate
aria-required="true" required: true tidak, pengecekannya kamu tulis sendiri

Form Bu Sri memeriksa sendiri nomor WhatsApp-nya (pelajaran form design), jadi dia memakai aria-required="true" di Nama lengkap dan Nomor WhatsApp; email opsional gak diberi. Pakai salah satu saja: spesifikasi ARIA in HTML dari W3C meminta aria-required="true" gak dipasang di elemen yang sudah punya required. Di latihan, beri aria-required="true" di input yang wajib diisi.

Pilihan yang berkelompok: fieldset dan legend

<fieldset class="nights">
  <legend>Jumlah malam</legend>
  <label><input type="radio" name="malam" value="1"> 1 malam</label>
  <label><input type="radio" name="malam" value="2" checked> 2 malam</label>
  <label><input type="radio" name="malam" value="3"> 3 malam</label>
</fieldset>

Error yang terdengar

Kolom yang salah butuh tiga hal (polanya sudah muncul di pelajaran feedback):

Ini memenuhi WCAG 3.3.1 (Error Identification): kolom yang salah ditandai, dan errornya dijelaskan dengan teks.

Skip link

Tiap halaman Bu Sri mulai dengan empat link navigasi. Pengguna keyboard harus melewatinya di setiap halaman: dari awal halaman, Tab ke-5 baru sampai di pilihan malam. Skip link adalah link pertama di halaman yang melompat langsung ke isi utama (WCAG 2.4.1, Bypass Blocks):

<a href="#isi" class="skip-link">Langsung ke isi utama</a>
<nav aria-label="Navigasi utama">...</nav>
<main id="isi" tabindex="-1">...</main>

<style>
  .skip-link { position: absolute; left: 8px; top: 8px; padding: 8px 12px; color: #fff; background: #1f2937; transform: translateY(-200%); }
  .skip-link:focus { transform: none; }
  main:focus { outline: none; }
</style>

Di latihan nanti, tambahkan <a href="#main-content" class="skip-link">Skip to main content</a> paling atas, sebelum <nav>. <main id="main-content"> sudah ada di kode awal; jangan ubah id-nya.

Fokus yang terlihat, urutan yang masuk akal

Urutan fokus mengikuti urutan elemen di HTML (WCAG 2.4.3, Focus Order). Di halaman Bu Sri: Beranda, Kamar, Lokasi, Pesanan, pilihan malam, Nama lengkap, Nomor WhatsApp, Email, tombol Pesan. Jangan memaksakan urutan dengan tabindex positif (tabindex="1" dan seterusnya); susun HTML-nya saja.

Fokus yang terlihat (WCAG 2.4.7, Focus Visible): pengguna keyboard harus selalu tahu di mana fokusnya.

a:focus-visible, input:focus-visible, button:focus-visible {
  outline: 3px solid #1f2937;
  outline-offset: 2px;
}

Jadi jawaban tebakannya: Tab ke-5 ada di radio "2 malam" (empat link, lalu grup radio yang cuma satu berhenti), tapi Pak Hadi gak bisa tahu, karena gak ada yang tergambar. Itu jawaban tebakannya.

⚠️ Jebakan yang sering ketemu

TL;DR: Tiap kolom butuh <label for> yang sama persis dengan id-nya; tanpa itu Chromium memakai placeholder sebagai nama ("0812 3456 7890"). Kolom wajib diumumkan dengan required (browser ikut mengecek) atau aria-required="true" (cuma diumumkan), salah satu saja. Pilihan radio dibungkus <fieldset> dengan <legend> ("Jumlah malam"); satu grup radio = satu berhenti Tab, panah memindahkan pilihan. Error: aria-invalid="true", aria-describedby ke contoh dan pesannya, dan role="alert" di paragraf error yang ada sejak awal (WCAG 3.3.1). Skip link <a href="#isi" class="skip-link"> paling atas, menunjuk id main yang ada, tersembunyi sampai difokus (WCAG 2.4.1). Urutan fokus = urutan HTML, tanpa tabindex positif (2.4.3). Fokus harus terlihat (2.4.7): :focus-visible muncul saat Tab dan biasanya gak saat klik mouse, jadi jangan hapus outline tanpa pengganti.

Yang akan kamu pelajari