Kotak Centang dan Tombol Radio

Pengelompokan fieldset dan legend serta konvensi name untuk checkbox dan radio.

Daftar isi

Kotak centang dan tombol radio adalah dua kontrol pilihan yang tampak serupa tetapi aturan pengelompokannya berbeda mendasar. Tombol radio membentuk kelompok eksklusif yang hanya boleh satu butir terpilih, sedangkan kotak centang berdiri sendiri-sendiri dan boleh tercentang sekaligus sebanyak yang diperlukan. Topik ini membahas atribut name, value, dan checked pada keduanya, pengelompokan visual dan semantik dengan fieldset dan legend, serta konvensi penamaan name[] untuk pengumpulan banyak nilai di server. Setelah membacanya, pilihan tunggal dan pilihan berganda dapat dibedakan dengan struktur yang benar.

Tombol radio sebagai kelompok eksklusif#

Kelompok tombol radio terbentuk dari beberapa input type="radio" yang berbagi nilai name yang sama, dan itulah satu-satunya mekanisme pengelompokannya. Browser memastikan hanya satu anggota kelompok yang terpilih, karena memilih salah satu otomatis melepas pilihan lainnya. Atribut value wajib diisi dengan makna yang jelas pada setiap anggota, karena nilai inilah yang dikirim, sedangkan teks di sampingnya hanya dibaca pengguna dan tidak pernah sampai ke server.

html Contoh: kelompok radio dengan satu name
<fieldset>
  <legend>Ruang baca favorit</legend>
  <label><input type="radio" name="ruang" value="barat" checked> Ruang barat</label>
  <label><input type="radio" name="ruang" value="timur"> Ruang timur</label>
  <label><input type="radio" name="ruang" value="tengah"> Ruang tengah</label>
</fieldset>

Atribut checked menetapkan anggota yang terpilih sejak halaman dimuat, dan tanpa atribut itu kelompoknya bermula tanpa pilihan. Kebutuhan wajib memilih juga ditangani HTML, yaitu atribut required cukup diletakkan pada salah satu anggota kelompok, dan browser menuntut pilihan pada kelompok itu saat formulir dikirim. Kesalahan yang sering terjadi adalah salah ketik satu nilai name, misalnya ruang dan ruanng, sehingga dua tombol radio membentuk kelompok berbeda dan keduanya dapat terpilih sekaligus tanpa peringatan apa pun.

Kotak centang yang independen#

Kotak centang tidak membentuk kelompok otomatis, karena setiap input type="checkbox" adalah pilihan ya atau tidak yang berdiri sendiri. Dua kotak centang yang berdampingan dapat tercentang bersamaan tanpa saling memengaruhi, dan itulah bentuk yang tepat untuk pilihan yang tidak saling meniadakan, misalnya daftar layanan yang boleh diaktifkan sekaligus. Nilai terkirimnya ditetapkan atribut value, dan tanpa atribut itu browser mengirimkan teks on sebagai nilai bawaan yang kurang bermakna.

Perilaku pengiriman kotak centang memerlukan perhatian khusus, yaitu kotak yang tidak tercentang tidak terkirim sama sekali, bukan terkirim dengan nilai kosong. Server yang menerima formulir tidak menemukan kuncinya, sehingga kode pemroses harus menangani ketiadaan kunci tersebut sebagai jawaban tidak. Perilaku ini berbeda dari kontrol teks yang tetap terkirim dengan nilai kosong, dan memahami perbedaannya mencegah kebingungan saat data diperiksa di sisi server.

Pasangan yang terkirim dari pilihan#

Skrip berikut meniru aturan pengiriman tersebut untuk memperlihatkan perbedaan hasilnya secara nyata. Fungsi pasanganTerkirim mengambil daftar kontrol beserta keadaan terpilihnya, lalu menyusun pasangan name=value sebagaimana browser mengirimkannya.

js
// Mensimulasikan pasangan name=value yang dikirim browser
// untuk radio, checkbox, dan kontrol biasa
function pasanganTerkirim(kontrol) {
  const hasil = [];
  for (const k of kontrol) {
    const berpilihan = k.tipe === "radio" || k.tipe === "checkbox";
    if (!berpilihan || k.terpilih) {
      hasil.push(`${k.name}=${k.value}`);
    }
  }
  return hasil;
}

const kontrol = [
  { name: "nama", tipe: "text", value: "Dewi", terpilih: true },
  { name: "kelas", tipe: "radio", value: "A", terpilih: false },
  { name: "kelas", tipe: "radio", value: "B", terpilih: true },
  { name: "kelas", tipe: "radio", value: "C", terpilih: false },
  { name: "ekstra[]", tipe: "checkbox", value: "futsal", terpilih: true },
  { name: "ekstra[]", tipe: "checkbox", value: "paduan-suara", terpilih: false },
  { name: "ekstra[]", tipe: "checkbox", value: "robotik", terpilih: true },
];

console.log("Skenario 1: sebagian kotak centang dicentang");
console.log(pasanganTerkirim(kontrol).join("\n"));

console.log("");
console.log("Skenario 2: seluruh kotak centang dilepas");
const tanpaCentang = kontrol.map(k =>
  k.tipe === "checkbox" ? { ...k, terpilih: false } : k
);
const sisaEkstra = pasanganTerkirim(tanpaCentang).filter(p => p.startsWith("ekstra[]"));
console.log(`pasangan ekstra[] yang terkirim: ${sisaEkstra.length}`);
text Keluaran
Skenario 1: sebagian kotak centang dicentang
nama=Dewi
kelas=B
ekstra[]=futsal
ekstra[]=robotik

Skenario 2: seluruh kotak centang dilepas
pasangan ekstra[] yang terkirim: 0

Keluaran skenario pertama memperlihatkan tiga aturan sekaligus, yaitu kelompok radio hanya menyumbang satu pasangan dari anggota yang terpilih, kotak centang menyumbang satu pasangan untuk setiap kotak yang tercentang, dan butir yang tidak terpilih tidak meninggalkan jejak. Skenario kedua menegaskan bahwa melepas seluruh kotak centang membuat kuncinya hilang sama sekali, dan jumlah pasangan yang tersisa adalah nol. Aturan inilah yang membuat kode server perlu menentukan perlakuan atas kunci yang tidak muncul, alih-alih mengharapkan nilai kosong.

fieldset dan legend untuk pengelompokan#

Elemen fieldset membungkus sekumpulan kontrol terkait, sedangkan legend memberi judul pada kumpulan itu. Perannya paling terasa pada kelompok radio, karena setiap tombol radio memiliki label sendiri, tetapi pertanyaan yang dijawab oleh seluruh kelompok belum terwakili di mana pun. Tanpa legend, pembaca layar membaca satu per satu label seperti Ruang barat tanpa konteks bahwa pertanyaannya adalah ruang baca favorit.

Pengelompokan fieldset juga bersifat fungsional, bukan sekadar bingkai visual. Atribut disabled pada fieldset mematikan seluruh kontrol di dalamnya sekaligus, dan validasi pada anggotanya ikut ditiadakan. Pembaca layar umumnya mengumumkan isi legend setiap kali fokus memasuki kontrol di dalam kelompoknya, sehingga konteks pertanyaan tetap terdengar bahkan saat pengguna menelusuri anggota satu per satu. Pola ini digunakan pula pada kelompok kotak centang dengan pertanyaan bersama, seperti layanan yang diaktifkan pada berkas utuh di bawah.

Konvensi penamaan name[] untuk banyak nilai#

Banyak nilai dari kotak centang tiba di server sebagai beberapa pasangan dengan kunci sama, dan setiap bahasa backend menanganinya dengan caranya sendiri. Konvensi name[] menambahkan tanda kurung siku pada akhir nama, dan bahasa seperti PHP mengumpulkan pasangan itu menjadi satu array secara otomatis. Nilai layanan[]=pinjam&layanan[]=daring tiba sebagai array dua butir tanpa kode pengumpul tambahan.

Konvensi ini milik sisi server, bukan bagian standar HTML, sehingga browser memperlakukannya sebagai nama biasa dan mengirimkannya apa adanya. Kerangka kerja yang tidak mengenal tanda kurung siku umumnya tetap mengumpulkan pasangan bernama sama menjadi daftar, sehingga perilaku akhirnya serupa. Penamaan dengan tanda kurung siku juga tetap sah sebagai nilai name biasa, sehingga tidak ada efek samping pada pengiriman atau validasi. Kesimpulan praktisnya, samakan penamaan dengan konvensi bahasa server yang digunakan, karena struktur data yang diterima mengikutinya.

Berkas utuh pilihan tunggal dan berganda#

Berkas berikut menyatukan topik ini dalam satu formulir anggota perpustakaan, yaitu kelompok radio ruang baca, kelompok kotak centang layanan dengan name[], dan satu kotak persetujuan yang wajib dicentang. Struktur fieldset dan legend digunakan pada kedua kelompok, dan label tiap butir dibuat implisit agar seluruh teksnya menjadi sasaran klik.

html pilihan.html
<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Contoh kotak centang dan tombol radio</title>
  <style>
    body { font-family: sans-serif; max-width: 34rem; margin: 0 auto; padding: 0 1rem; }
    fieldset { margin-bottom: 1rem; }
    label { display: block; padding: 0.2rem 0; }
  </style>
</head>
<body>
  <h1>Formulir anggota perpustakaan</h1>

  <form action="/anggota" method="post">
    <fieldset>
      <legend>Ruang baca favorit</legend>
      <label><input type="radio" name="ruang" value="barat" checked> Ruang barat</label>
      <label><input type="radio" name="ruang" value="timur"> Ruang timur</label>
      <label><input type="radio" name="ruang" value="tengah"> Ruang tengah</label>
    </fieldset>

    <fieldset>
      <legend>Layanan yang diaktifkan</legend>
      <label><input type="checkbox" name="layanan[]" value="pinjam"> Peminjaman beranda</label>
      <label><input type="checkbox" name="layanan[]" value="rujukan"> Buku rujukan</label>
      <label><input type="checkbox" name="layanan[]" value="daring"> Koleksi digital</label>
      <label><input type="checkbox" name="persetujuan" value="ya" required> Menyetujui tata tertib</label>
    </fieldset>

    <p><button type="submit">Daftarkan</button></p>
  </form>
</body>
</html>

Buka berkasnya di browser, pilih salah satu ruang baca, lalu amati bahwa memilih ruang lain otomatis melepaskan pilihan sebelumnya. Coba kirim tanpa mencentang persetujuan, dan pengiriman ditahan dengan pesan error pada kotak itu, karena required-nya terpasang. Kirim formulir dengan tab Network pada DevTools terbuka, dan pasangan ruang=... bersama deret layanan[] terlihat pada data permintaannya, lengkap dengan persetujuan=ya yang wajib hadir agar pengiriman diterima.

Kesalahan umum#

  • Memberi nilai name berbeda pada tombol radio yang seharusnya satu kelompok. Setiap tombol menjadi kelompok sendiri sehingga lebih dari satu pilihan aktif sekaligus. Samakan name pada seluruh anggota kelompoknya.
  • Menghilangkan atribut value pada radio dan kotak centang. Nilai yang terkirim menjadi teks on untuk semua butirnya, sehingga server tidak dapat membedakan pilihannya.
  • Mengharapkan kotak centang yang tidak tercentang mengirim nilai kosong. Kontrol itu tidak terkirim sama sekali, sehingga tangani ketiadaan kuncinya di server.
  • Menuliskan pertanyaan kelompok sebagai label salah satu anggota. Konteksnya hanya melekat pada satu tombol, sedangkan fieldset dan legend memberi nama yang terbaca untuk seluruh kelompok.

Ringkasan#

  • Tombol radio berbagi name yang sama membentuk kelompok eksklusif, dengan checked sebagai pilihan awal dan value sebagai nilai yang terkirim.
  • Kotak centang berdiri independen, mengirim nilai value-nya hanya saat tercentang, dan tidak terkirim sama sekali saat dilepas.
  • fieldset dan legend memberi pengelompokan semantik beserta judulnya, dan disabled pada fieldset mematikan seluruh anggotanya.
  • Konvensi name[] mengumpulkan banyak nilai menjadi array di server, dan penamaannya mengikuti konvensi bahasa backend yang digunakan.

Referensi#