Form adalah elemen yang paling menuntut ketelitian aksesibilitas, karena di sanalah pengunjung mengeluarkan data dan mengambil keputusan: mendaftar, membayar, atau mengirim pesan. Section Forms telah kita pakai untuk menyusun strukturnya, dan section Form Validation untuk aturan isian. Kini komponen itu kita angkat ulang dengan satu pertanyaan: apa yang dengar dan alami pengguna screen reader atau keyboard di setiap langkah pengisian?
Label Terhubung Secara Eksplisit #
Dasar form aksesibel adalah pasangan label dan kontrol yang terhubung lewat for dan id. Koneksi ini menghasilkan dua manfaat sekaligus: screen reader membacakan label saat kontrol menerima fokus, dan klik pada teks label ikut mencentang kontrol sehingga target sentuh menjadi luas. Cara kedua adalah membungkus kontrol di dalam label; hasilnya sama, tetapi cara for lebih eksplisit dan mudah dibaca di kode panjang.
Perbandingan berikut mengingatkan mengapa placeholder bukan pengganti label, seperti yang sempat kita singgung pada chapter Required dan Placeholder:
| Aspek | label | placeholder |
|---|---|---|
| Hilang saat pengguna mengetik | tidak | ya |
| Dibacakan screen reader sebagai nama | selalu | tidak dijamin |
| Jadi sumber accessible name | ya | tidak |
Kelompok Kontrol dengan fieldset dan legend #
Pertanyaan yang dijawab beberapa kontrol sekaligus — misalnya satu pilihan pembayaran dari dua radio — perlu dibungkus fieldset dengan judul di elemen legend. Screen reader mengumumkan isi legend bersama setiap kontrol di dalam grup, sehingga “Transfer bank” terdengar sebagai “Transfer bank, Metode Pembayaran, tombol pilihan”. Tanpa grup, pengguna yang melompat dengan Tab mendengar pilihan-pilihan lepas tanpa konteks pertanyaannya.
Petunjuk Format dengan aria-describedby #
Petunjuk kecil seperti contoh format sering kita tempel di bawah input, dan agar petunjuk itu ikut terdengar ia harus disambungkan lewat aria-describedby:
<label for="telepon">Nomor telepon (wajib)</label>
<input type="tel" id="telepon" name="telepon" autocomplete="tel"
aria-describedby="petunjuk-telepon">
<span id="petunjuk-telepon">Format 08xx, tanpa spasi.</span>Urutan bacaannya menjadi utuh: label dulu, lalu jenis kontrol, lalu isi petunjuk. Atribut yang sama menampung beberapa id sekaligus, dipisah spasi, sehingga petunjuk dan pesan kesalahan bisa menyatu pada satu kontrol.
Menandai Input Wajib dengan Teks #
Atribut required memenuhi sisi validasi, tetapi sisi informasi butuh teks yang terbaca. Tulis kata “wajib” di dalam label — “Nama lengkap (wajib)” — sehingga kebutuhannya diketahui sebelum pengguna mengetik. Menandai isian penting hanya dengan warna merah melanggar prinsip WCAG bahwa warna tak boleh menjadi satu-satunya penanda; bintang * boleh dipakai asalkan diberi keterangan artinya di awal form.
Pesan Kesalahan yang Terhubung #
Pesan kesalahan yang muncul jauh dari kolomnya, atau muncul tanpa diumumkan, memaksa pengguna menebak letak salahnya. Pola yang benar menempatkan pesan di dekat kolom, memberinya id, lalu merujuknya pada aria-describedby kolom bersama petunjuk. Saat validasi gagal, atribut aria-invalid="true" menyatakan kolom bermasalah; pembaruan nilainya dilakukan script, dan sintaks JavaScript-nya kita pelajari pada section tersendiri.
Memudahkan Pengisian dengan autocomplete #
Atribut autocomplete dengan nilai token standar memberi tahu browser data apa yang diharapkan sebuah kolom:
| Token | Data yang diisi |
|---|---|
name | nama lengkap |
email | alamat email |
tel | nomor telepon |
street-address | alamat jalan |
postal-code | kode pos |
new-password | kata sandi baru saat mendaftar |
Sebagian token bersifat multiline sehingga hanya sah pada textarea, dan street-address termasuk di dalamnya; kolom satu baris memakai token lain. Manfaat atribut ini melampaui kenyamanan: browser mengisi kolom secara akurat tanpa mengetik, membantu pengguna dengan gangguan motorik maupun kognitif, dan token new-password membantu pengelola sandi membuat nilai yang aman.
Menyusun Form Lengkap yang Aksesibel #
Semua pola di atas berjumpa pada satu form pemesanan:
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Form Pemesanan Tanaman</title>
</head>
<body>
<h1>Form Pemesanan Tanaman</h1>
<p>Isian bertanda (wajib) harus diisi sebelum form dapat dikirim.</p>
<form action="www.example.com/pesan" method="post">
<fieldset>
<legend>Data Pemesan</legend>
<p>
<label for="nama">Nama lengkap (wajib)</label>
<input type="text" id="nama" name="nama" autocomplete="name" required>
</p>
<p>
<label for="email">Email (wajib)</label>
<input type="email" id="email" name="email" autocomplete="email" required
aria-describedby="petunjuk-email pesan-email">
<span id="petunjuk-email">Contoh: [email protected]</span>
<strong id="pesan-email" hidden>Format email belum tepat.</strong>
</p>
</fieldset>
<fieldset>
<legend>Alamat Pengiriman</legend>
<p>
<label for="alamat">Jalan dan nomor rumah</label>
<textarea id="alamat" name="alamat" autocomplete="street-address"></textarea>
</p>
<p>
<label for="kode-pos">Kode pos (wajib)</label>
<input type="text" id="kode-pos" name="kode-pos" autocomplete="postal-code"
required pattern="[0-9]{5}">
</p>
</fieldset>
<fieldset>
<legend>Metode Pembayaran</legend>
<p>
<input type="radio" id="bayar-transfer" name="pembayaran" value="transfer">
<label for="bayar-transfer">Transfer bank</label>
</p>
<p>
<input type="radio" id="bayar-cod" name="pembayaran" value="cod">
<label for="bayar-cod">Bayar di tempat</label>
</p>
</fieldset>
<button type="submit">Kirim pesanan</button>
</form>
</body>
</html>Output yang Dihasilkan:
Pengguna keyboard menekan Tab; screen reader mengumumkan:
- "Data Pemesan, grup" (legend + fieldset)
- "Nama lengkap (wajib), teks, wajib diisi"
- "Email (wajib), email, wajib diisi,
Contoh: [email protected]" (petunjuk ikut dibaca)
Menekan panah pada grup pembayaran berpindah antara dua pilihan.Mari kita bedah pola yang bekerja di form ini:
- Baris 12-25 (
fieldsetpertama):legend“Data Pemesan” memberi konteks pada seluruh isian identitas di dalamnya. - Baris 20-23 (input email):
aria-describedbymerujuk duaidsekaligus — petunjuk format dan pesan kesalahan — danstrongdiberihiddenkarena pesan belum relevan. - Baris 16 dan 20 (
required+ teks wajib): kebutuhan isian tersampaikan dua kali, untuk validasi browser dan untuk pembaca. - Baris 33-35 (input kode pos): pola
pattern="[0-9]{5}"dari chapter Pola Validasi dipasangkan dengan label yang menyebut wajib. - Baris 38-48 (fieldset pembayaran): dua
radioterkelompok dalamlegend“Metode Pembayaran”, sehingga tiap pilihan terdengar lengkap dengan pertanyaannya.
Form yang baik beres; kelompok data berikutnya yang menuntut struktur eksplisit adalah tabel. Chapter berikutnya kembali ke tabel dari sisi pengalaman screen reader yang membaca sel demi sel.
Referensi resmi untuk pendalaman:
- W3C WAI — Forms Tutorial
- MDN Web Docs — Elemen label
- MDN Web Docs — Atribut autocomplete
- web.dev — Learn Forms: Accessibility
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
contoh-form-aksesibel.html
Unduh berkas<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Form Pemesanan Tanaman</title>
</head>
<body>
<h1>Form Pemesanan Tanaman</h1>
<p>Isian bertanda (wajib) harus diisi sebelum form dapat dikirim.</p>
<form action="www.example.com/pesan" method="post">
<fieldset>
<legend>Data Pemesan</legend>
<p>
<label for="nama">Nama lengkap (wajib)</label>
<input type="text" id="nama" name="nama" autocomplete="name" required>
</p>
<p>
<label for="email">Email (wajib)</label>
<input type="email" id="email" name="email" autocomplete="email" required
aria-describedby="petunjuk-email pesan-email">
<span id="petunjuk-email">Contoh: [email protected]</span>
<strong id="pesan-email" hidden>Format email belum tepat.</strong>
</p>
</fieldset>
<fieldset>
<legend>Alamat Pengiriman</legend>
<p>
<label for="alamat">Jalan dan nomor rumah</label>
<textarea id="alamat" name="alamat" autocomplete="street-address"></textarea>
</p>
<p>
<label for="kode-pos">Kode pos (wajib)</label>
<input type="text" id="kode-pos" name="kode-pos" autocomplete="postal-code"
required pattern="[0-9]{5}">
</p>
</fieldset>
<fieldset>
<legend>Metode Pembayaran</legend>
<p>
<input type="radio" id="bayar-transfer" name="pembayaran" value="transfer">
<label for="bayar-transfer">Transfer bank</label>
</p>
<p>
<input type="radio" id="bayar-cod" name="pembayaran" value="cod">
<label for="bayar-cod">Bayar di tempat</label>
</p>
</fieldset>
<button type="submit">Kirim pesanan</button>
</form>
</body>
</html>