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:

Aspeklabelplaceholder
Hilang saat pengguna mengetiktidakya
Dibacakan screen reader sebagai namaselalutidak dijamin
Jadi sumber accessible nameyatidak

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:

html
<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:

TokenData yang diisi
namenama lengkap
emailalamat email
telnomor telepon
street-addressalamat jalan
postal-codekode pos
new-passwordkata 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:

text
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:

  1. Baris 12-25 (fieldset pertama): legend “Data Pemesan” memberi konteks pada seluruh isian identitas di dalamnya.
  2. Baris 20-23 (input email): aria-describedby merujuk dua id sekaligus — petunjuk format dan pesan kesalahan — dan strong diberi hidden karena pesan belum relevan.
  3. Baris 16 dan 20 (required + teks wajib): kebutuhan isian tersampaikan dua kali, untuk validasi browser dan untuk pembaca.
  4. Baris 33-35 (input kode pos): pola pattern="[0-9]{5}" dari chapter Pola Validasi dipasangkan dengan label yang menyebut wajib.
  5. Baris 38-48 (fieldset pembayaran): dua radio terkelompok dalam legend “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:

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

contoh-form-aksesibel.html

Unduh berkas
html
<!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>