Ilustrasi tabel data, checklist, dan kolom form input

Episode lalu kamu belajar menghubungkan halaman dan menempelkan media. Sekarang kita masuk ke materi yang paling sering dipakai di web nyata: daftar, tabel, dan form. Ini episode keempat dari seri HTML Basic. Kalau episode sebelumnya soal "menampilkan", episode ini soal "mengatur" dan "menerima". Tabel mengatur data supaya enak dibaca, form menerima data dari pengunjung. Hampir tidak ada website profesional yang tidak memakai ketiganya.

Dua persepsi salah yang perlu diluruskan. Pertama, banyak pemula memakai tabel untuk mengatur tata letak halaman, misalnya menaruh menu di kolom kiri dan konten di kolom kanan. Itu praktik dari tahun 2000-an yang sudah mati. Tabel hanya untuk data tabular, data yang masuk akal kalau dibuka di Excel. Tata letak halaman adalah urusan CSS, yang akan kamu pelajari di seri berikutnya. Kedua, banyak yang mengira form itu cuma soal tampilan kotak input. Padahal form adalah soal komunikasi: setiap input harus punya label yang terhubung, tipe yang tepat, dan aturan validasi. Form yang asal jadi membuat frustrasi, terutama bagi pengguna keyboard dan screen reader.

List, Cara Paling Rapi Menyusun Daftar

Ada tiga jenis list di HTML. <ul> (unordered list) untuk daftar tanpa urutan, memakai bullet. <ol> (ordered list) untuk daftar berurutan, memakai angka. Dan <dl> (description list) untuk pasangan istilah dan penjelasan, seperti kamus. Setiap item di dalam ul dan ol dibungkus <li>.

<ul>
  <li>Nasi goreng</li>
  <li>Mie ayam</li>
  <li>Soto lamongan</li>
</ul>

<ol>
  <li>Rebus air sampai mendidih</li>
  <li>Masukkan mie dan bumbu</li>
  <li>Tunggu tiga menit, sajikan</li>
</ol>

<dl>
  <dt>HTML</dt>
  <dd>Bahasa untuk struktur halaman web</dd>
  <dt>CSS</dt>
  <dd>Bahasa untuk tampilan halaman web</dd>
</dl>

Aturan berpikirnya sederhana: kalau urutannya penting (langkah resep, ranking), pakai ol. Kalau tidak penting (daftar belanja, menu navigasi), pakai ul. Kalau isinya pasangan istilah-penjelasan, pakai dl. Menu navigasi website hampir selalu dibuat dengan ul berisi link, itu standar industri.

Berhenti dan tebak dulu! Kamu mau membuat daftar "5 film terbaik tahun ini" yang berperingkat dari nomor 1 sampai 5. Tag apa yang paling tepat?

A. <ul>  B. <ol>  C. <dl>
Jawaban: B. Karena ada peringkat, urutan angkanya bermakna. <ol> memberi nomor otomatis dan memberi tahu screen reader bahwa ini daftar berurutan. <ul> hanya memberi bullet tanpa makna urutan, dan <dl> untuk pasangan istilah-penjelasan, bukan ranking.

Tabel untuk Data, Bukan untuk Layout

Ingat aturan emasnya: kalau datanya masuk akal dibuka di spreadsheet, pakai tabel. Kalau tujuannya cuma "pengen dua kolom di halaman", itu bukan tabel, itu layout, dan solusinya CSS Flexbox atau Grid nanti.

Struktur tabel profesional punya tiga zona: <thead> untuk baris judul kolom, <tbody> untuk isi data, dan <tfoot> untuk ringkasan atau total. Sel judul memakai <th>, sel data memakai <td>. Baris dibungkus <tr>.

<table>
  <caption>Jadwal piket kelas</caption>
  <thead>
    <tr>
      <th scope="col">Hari</th>
      <th scope="col">Nama</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Senin</th>
      <td>Budi</td>
    </tr>
    <tr>
      <th scope="row">Selasa</th>
      <td>Ani</td>
    </tr>
  </tbody>
</table>

Perhatikan dua detail yang membedakan tabel amatir dan profesional. <caption> memberi judul tabel yang dibaca screen reader sebagai identitas tabel. Atribut scope="col" atau scope="row" memberi tahu screen reader judul mana yang menjadi kepala untuk kolom atau baris tertentu. Tanpa ini, pengguna tunanetra hanya mendengar deretan angka tanpa tahu angka itu milik siapa. Kadang satu sel perlu melebar ke beberapa kolom (colspan) atau beberapa baris (rowspan), misalnya judul "Kontak" yang menaungi kolom Email dan Telepon.

Berhenti dan tebak dulu! Apa beda fungsi <th> dan <td> selain tampilannya yang tebal dan rata tengah?

Jawaban: <th> memberi makna "ini judul", bukan cuma gaya. Screen reader mengumumkan sel <th> sebagai header, sehingga pengguna tunanetra bisa memahami struktur tabel: baris ini tentang siapa, kolom ini tentang apa. Kalau semua sel memakai <td>, screen reader hanya membacakan data mentah tanpa konteks. Tampilan tebal itu cuma bonus dari browser, makna semantiknya yang utama.

Form, Jembatan Dua Arah dengan Pengunjung

Sampai titik ini, semua yang kamu buat bersifat satu arah: kamu menampilkan, pengunjung membaca. Form membalik arusnya. Inilah fondasi dari halaman login, pendaftaran, kolom komentar, dan pencarian.

Struktur dasarnya: <form> sebagai wadah, <label> sebagai nama tiap kolom, dan <input> sebagai kolomnya. Aturan yang tidak boleh dilanggar: setiap input wajib punya label, dan atribut for pada label harus sama persis dengan id pada input. Kenapa repot? Karena dengan begitu, mengklik teks label akan otomatis mengaktifkan inputnya, dan screen reader tahu label mana milik input mana.

<form action="/daftar" method="post">
  <label for="nama">Nama lengkap</label>
  <input type="text" id="nama" name="nama" required>

  <label for="email">Email</label>
  <input type="email" id="email" name="email" required>

  <label for="umur">Umur</label>
  <input type="number" id="umur" name="umur" min="13" max="120">

  <button type="submit">Daftar</button>
</form>

Atribut type pada input bukan hiasan. type="email" membuat browser memeriksa format email secara otomatis dan menampilkan keyboard khusus email di HP. type="number" memunculkan keyboard angka. type="password" menyamarkan ketikan. type="date" memunculkan pemilih tanggal. Memilih tipe yang tepat adalah cara termudah membuat form yang ramah, terutama di HP.

HTML juga punya validasi bawaan gratis: required mewajibkan isian, minlength dan maxlength mengatur panjang teks, min dan max membatasi angka, dan pattern memeriksa pola dengan regex sederhana. Browser akan menampilkan pesan error otomatis kalau aturan dilanggar, tanpa sebaris pun JavaScript. Catatan penting: validasi ini hanya untuk kenyamanan pengguna. Untuk keamanan sungguhan, validasi harus diulang di server, karena aturan HTML bisa dilewati dengan mudah.

Untuk pilihan, ada tiga kontrol utama:

  • <select> dengan <option>: menu dropdown, cocok untuk daftar panjang seperti pilihan kota.
  • type="radio": pilihan tunggal dari beberapa opsi. Semua radio dalam satu kelompok harus punya name yang sama supaya hanya satu yang bisa dipilih.
  • type="checkbox": pilihan ganda, masing-masing berdiri sendiri.
  • <textarea>: kotak teks multi-baris untuk pesan atau komentar.
<fieldset>
  <legend>Metode kontak favorit</legend>
  <input type="radio" id="k-email" name="kontak" value="email">
  <label for="k-email">Email</label>
  <input type="radio" id="k-wa" name="kontak" value="whatsapp">
  <label for="k-wa">WhatsApp</label>
</fieldset>

<fieldset> dan <legend> mengelompokkan input yang berhubungan, seperti kotak di formulir kertas beserta judul kotaknya. Screen reader akan mengumumkan judul kelompoknya sebelum membacakan tiap pilihan.

Kuis cepat: Manakah form yang paling benar?

Atribut Name dan Cara Data Dikirim

Ada satu atribut yang belum kita bahas tapi krusial: name. Kalau id adalah nama panggilan untuk browser dan JavaScript, name adalah nama resmi yang dikirim ke server. Saat form di-submit, browser mengemas data sebagai pasangan name=nilai. Input tanpa name tidak akan terkirim, datanya hilang di jalan. Itu sebabnya contoh form di artikel ini selalu menulis id dan name berpasangan.

Dua atribut form itu sendiri juga perlu dipahami: action adalah alamat tujuan data dikirim (misalnya /daftar), dan method adalah cara pengirimannya. method="get" menempelkan data di URL (terlihat di address bar, cocok untuk form pencarian), method="post" menyembunyikannya di badan request (cocok untuk pendaftaran dan login). Untuk sekarang, cukup pahami konsepnya. Detail pengiriman data adalah urusan backend yang akan kamu pelajari di seri PHP dan Node.js nanti.

Berhenti dan tebak dulu! Form ini punya dua radio button. Apa yang terjadi kalau pengguna memilih "Ya" lalu memilih "Tidak"?

<input type="radio" id="y" name="ikut" value="ya">
<label for="y">Ya</label>
<input type="radio" id="t" name="ikut" value="tidak">
<label for="t">Tidak</label>
Jawaban: pilihan "Ya" otomatis batal, hanya "Tidak" yang terpilih. Itulah fungsi atribut name yang sama pada radio button: dia mendefinisikan satu kelompok pilihan tunggal. Browser tahu keduanya adalah jawaban untuk pertanyaan yang sama, sehingga hanya satu yang boleh aktif. Kalau name-nya beda, keduanya bisa terpilih bersamaan dan maknanya rusak. Untuk checkbox yang memang boleh dipilih banyak, tiap checkbox punya name sendiri atau name yang sama dengan value berbeda, tergantung kebutuhan server.

Satu jebakan terakhir soal placeholder. Banyak pemula memakai placeholder sebagai pengganti label karena terlihat rapi. Jangan. Placeholder hilang begitu pengguna mulai mengetik, sehingga di tengah mengisi form dia lupa kolom itu untuk apa. Screen reader pun tidak selalu membacakannya dengan andal. Placeholder adalah contoh format, label adalah identitas. Keduanya punya peran, tidak saling menggantikan.

Latihan: Form Pendaftaran Ekstrakurikuler

Buat file daftar.html dan buat form pendaftaran ekstrakurikuler sekolahmu:

  1. Input nama (text, required), email (email, required), dan tanggal lahir (date).
  2. Dropdown pilihan ekstrakurikuler dengan <select> berisi minimal 4 opsi.
  3. Radio button "Pernah ikut sebelumnya?" (Ya/Tidak) yang dikelompokkan dengan <fieldset> dan <legend>.
  4. Checkbox "Saya setuju mengikuti semua kegiatan" yang wajib dicentang (pakai required).
  5. <textarea> untuk alasan ingin ikut, dibatasi maksimal 200 karakter.
  6. Uji formanmu: coba submit dalam keadaan kosong dan perhatikan pesan error bawaan browser. Lalu coba isi email dengan teks tanpa @ dan submit lagi. Catat apa yang terjadi.

Di episode berikutnya, seri HTML Basic mencapai puncaknya: HTML Semantic dan Proyek Halaman Profil. Kamu akan belajar memberi makna pada struktur halaman dengan tag seperti header, nav, main, dan footer, lalu menggabungkan semua yang sudah dipelajari menjadi satu halaman profil utuh. Ini proyek pertama yang layak kamu pamerkan.