Pada section Forms, tombol bertugas mengirim formulir. Di luar form, elemen button tetap sah dan justru menjadi komponen pemicu interaksi yang paling sering dipakai: membuka dialog, mengalihkan popover, atau mengubah mode halaman. Chapter ini membahas aturan button di luar form, peran type="button", pola tombol dengan dialog dan popover, perbedaan disabled dengan aria-disabled, serta tombol toggle dengan aria-pressed.

Tombol di Luar Form #

Elemen button termasuk konten aliran (flow content), sehingga boleh ditulis di mana pun isi body boleh berada. Tanpa form di sekitarnya, tombol tidak punya perilaku bawaan: kliknya tidak mengirim data ke mana pun. Perilakunya datang dari JavaScript, yaitu listener click yang dipasang seperti pada section HTML dan JavaScript. Dari sinilah pola tombol pemicu bermula: satu tombol dengan id, satu listener, lalu satu aksi.

Mengapa type=“button” Tetap Penting #

Atribut type pada button bernilai default submit. Di luar form, nilai default itu tidak berefek karena tidak ada form untuk dikirim. Masalah muncul saat markup berubah: tombol yang pindah ke dalam form — misalnya hasil refactor — tiba-tiba ikut mengirim form dan memicu validasinya setiap ditekan. Menuliskan type="button" secara eksplisit menegaskan niat kita sekaligus melindungi halaman dari perubahan markup seperti itu.

Nilai typePerilaku
submit (default)Mengirim form terdekat dan memicu validasinya
resetMengosongkan isian form terdekat
buttonTanpa perilaku bawaan; aksinya ditulis JavaScript

Pola Tombol dan Dialog atau Popover #

Dua pola pemicu yang paling umum adalah tombol yang membuka dialog dan tombol yang mengalihkan popover. Untuk dialog, listener tombol memanggil showModal() seperti pada chapter sebelumnya. Untuk popover, HTML menyediakan jalur tanpa JavaScript: elemen dengan atribut global popover bisa dialihkan oleh tombol yang membawa atribut popovertarget.

html Tombol pengalih popover tanpa JavaScript
<button type="button" popovertarget="panel-info">Info pengiriman</button>
<div id="panel-info" popover>Gratis untuk pembelian di atas Rp100.000.</div>

Menekan tombol itu membuat browser menampilkan dan menyembunyikan panel secara bergantian, lengkap dengan penempatan top layer bawaan. Pola ini cocok untuk konten kecil seperti keterangan singkat; panel yang kompleks tetap lebih tepat memakai dialog.

disabled dan aria-disabled #

Atribut boolean disabled menonaktifkan tombol sepenuhnya: elemen tidak bisa difokus, tidak muncul dalam urutan Tab, dan tidak dibacakan pembaca layar. Sebaliknya, aria-disabled="true" hanya mengumumkan bahwa tombol sedang tidak tersedia, sementara elemen tetap bisa difokuskan dan tetap bisa ditekan. Karena itu pilihan aria-disabled menuntut JavaScript yang tetap menolak aksinya; pakai disabled bila tombol memang harus mati total.

Tombol Toggle dengan aria-pressed #

Tombol toggle menyatakan keadaan dua arah: tersimpan atau belum, aktif atau tidak. Atribut ARIA aria-pressed dengan nilai true atau false diumumkan pembaca layar sebagai tombol yang “ditekan” atau “tidak ditekan”. Nilainya kita perbarui di listener yang sama dengan perubahan aksinya, dan CSS bisa membaca keadaan itu lewat selector [aria-pressed="true"]. Dengan begitu tampilan, perilaku, dan pengumuman pembaca layar bergerak bersama.

Contoh: Tombol Favorit dan Catatan #

Kita gabungkan pola di atas pada halaman resep Budi: satu tombol toggle “Simpan ke favorit” dengan aria-pressed, dan satu tombol yang membuka dialog catatan singkat.

<!doctype html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Tombol dan Interaksi</title>
  <style>
    body {
      font-family: sans-serif;
      max-width: 480px;
      margin: 24px auto;
      line-height: 1.6;
    }
    button {
      padding: 8px 14px;
      border-radius: 6px;
      border: 1px solid #6b7280;
      background: #f3f4f6;
      cursor: pointer;
    }
    #tombol-favorit[aria-pressed="true"] {
      background: #1a6b54;
      color: #ffffff;
      border-color: #1a6b54;
    }
    dialog {
      border: none;
      border-radius: 8px;
      padding: 20px;
    }
    dialog::backdrop {
      background: rgba(15, 23, 42, 0.55);
    }
  </style>
</head>
<body>
  <h1>Resep Rendang Budi</h1>
  <p>Tekan tombol untuk menyimpan resep ini atau membuka catatan singkat.</p>
  <button id="tombol-favorit" type="button" aria-pressed="false">Simpan ke favorit</button>
  <button id="tombol-catatan" type="button">Buka catatan</button>

  <dialog id="dialog-catatan">
    <p>Waktu memasak: 4 jam. Sajikan bersama nasi hangat.</p>
    <form method="dialog">
      <button type="submit">Tutup</button>
    </form>
  </dialog>

  <script>
    const tombolFavorit = document.querySelector("#tombol-favorit");
    const tombolCatatan = document.querySelector("#tombol-catatan");
    const dialog = document.querySelector("#dialog-catatan");

    tombolFavorit.addEventListener("click", function () {
      if (tombolFavorit.getAttribute("aria-pressed") === "true") {
        tombolFavorit.setAttribute("aria-pressed", "false");
      } else {
        tombolFavorit.setAttribute("aria-pressed", "true");
      }
    });

    tombolCatatan.addEventListener("click", function () {
      dialog.showModal();
    });
  </script>
</body>
</html>

Output yang Dihasilkan:

text
Saat halaman baru dibuka:
  - Kedua tombol tampil dengan latar abu-abu muda
Tombol "Simpan ke favorit" ditekan:
  - Latar tombol berubah hijau karena selector [aria-pressed="true"]
  - Pembaca layar mengumumkan tombol dalam keadaan ditekan
Tombol "Simpan ke favorit" ditekan lagi:
  - Latar kembali abu-abu dan keadaan ditekan dicabut
Tombol "Buka catatan" ditekan:
  - Dialog tampil sebagai modal dengan latar halaman menggelap

Mari kita bedah isi halaman itu:

  1. Atribut type="button" pada kedua tombol: menegaskan tidak ada tombol yang berperan mengirim form.
  2. aria-pressed="false" pada tombol favorit: keadaan awal tombol toggle, disimpan sebagai nilai atribut.
  3. Listener #tombol-favorit: getAttribute("aria-pressed") membaca nilai atribut saat ini — kebalikan dari setAttribute — lalu cabang if menukarnya menjadi true atau false.
  4. Selector [aria-pressed="true"]: CSS membaca keadaan yang sama sehingga warna tombol ikut berganti tanpa class tambahan.
  5. Listener #tombol-catatan: memanggil dialog.showModal() pada dialog catatan.
  6. Form method="dialog" di dalam dialog: tombol “Tutup” menutup dialog tanpa satu baris JavaScript tambahan.

Satu catatan gaya: biarkan teks label tombol tetap sama, dan nyatakan perubahannya lewat aria-pressed beserta gaya CSS. Label yang berganti-ganti teks membuat nama tombol berubah pula, sehingga pengguna pembaca layar mudah kehilangan jejak.

Dengan tombol yang tepat, setiap pola interaktif pada section ini punya pemicu yang dapat diandalkan. Chapter berikutnya membahas disclosure sebagai pola UI utuh dan membandingkan versi native dengan versi custom.

Referensi resmi untuk pendalaman:

Berkas Sumber

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

tombol-interaksi.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>Tombol dan Interaksi</title>
  <style>
    body {
      font-family: sans-serif;
      max-width: 480px;
      margin: 24px auto;
      line-height: 1.6;
    }
    button {
      padding: 8px 14px;
      border-radius: 6px;
      border: 1px solid #6b7280;
      background: #f3f4f6;
      cursor: pointer;
    }
    #tombol-favorit[aria-pressed="true"] {
      background: #1a6b54;
      color: #ffffff;
      border-color: #1a6b54;
    }
    dialog {
      border: none;
      border-radius: 8px;
      padding: 20px;
    }
    dialog::backdrop {
      background: rgba(15, 23, 42, 0.55);
    }
  </style>
</head>
<body>
  <h1>Resep Rendang Budi</h1>
  <p>Tekan tombol untuk menyimpan resep ini atau membuka catatan singkat.</p>
  <button id="tombol-favorit" type="button" aria-pressed="false">Simpan ke favorit</button>
  <button id="tombol-catatan" type="button">Buka catatan</button>

  <dialog id="dialog-catatan">
    <p>Waktu memasak: 4 jam. Sajikan bersama nasi hangat.</p>
    <form method="dialog">
      <button type="submit">Tutup</button>
    </form>
  </dialog>

  <script>
    const tombolFavorit = document.querySelector("#tombol-favorit");
    const tombolCatatan = document.querySelector("#tombol-catatan");
    const dialog = document.querySelector("#dialog-catatan");

    tombolFavorit.addEventListener("click", function () {
      if (tombolFavorit.getAttribute("aria-pressed") === "true") {
        tombolFavorit.setAttribute("aria-pressed", "false");
      } else {
        tombolFavorit.setAttribute("aria-pressed", "true");
      }
    });

    tombolCatatan.addEventListener("click", function () {
      dialog.showModal();
    });
  </script>
</body>
</html>