Kotak konfirmasi sebelum menghapus data, jendela pemberitahuan, dan panel pengaturan kecil memerlukan satu wadah yang tampil di atas halaman. Dulu pola ini dirakit dari div, CSS, dan deretan JavaScript; kini HTML menyediakan elemen dialog yang menangani lapisan, fokus, dan tombol Escape secara bawaan. Pada chapter ini kita membedah dua mode dialog, atribut dan method utamanya, styling ::backdrop, lalu merakit satu dialog konfirmasi yang berfungsi penuh.

Dua Mode: Modal dan Non-modal #

Elemen dialog mewakili kotak dialog atau komponen interaktif lain yang tampil di atas halaman. Method show() membukanya dalam mode non-modal: dialog tampil seperti elemen biasa, dan pengunjung masih bebas berpindah ke bagian halaman mana pun. Method showModal() membukanya dalam mode modal: dialog naik ke top layer — lapisan tertinggi di atas seluruh konten — sementara halaman di belakangnya menjadi inert sehingga tidak bisa diklik atau difokuskan. Mode modal juga merender pseudo-element ::backdrop yang menutupi layar di belakang dialog.

Aspekshow() — non-modalshowModal() — modal
Interaksi sisa halamanTetap aktifTerkunci (inert)
::backdropTidak direnderDirender dan bisa distyle
Tombol EscapeTidak menutup dialogMenutup dialog otomatis
Pengelolaan fokusDiatur sendiriPindah ke dialog, kembali otomatis saat ditutup

Atribut open dan method close() #

Secara default elemen dialog tidak dirender: stylesheet bawaan browser menetapkan display: none kepadanya. Atribut open yang tertulis di markup membuatnya tampil dalam mode non-modal, mirip hasil pemanggilan show(). Untuk menutup dialog dari JavaScript, panggil method close(); browser lalu menyembunyikan dialog dan memicu event close. Method close() juga menerima satu argumen opsional yang disimpan sebagai returnValue.

returnValue lewat form method=“dialog” #

Cara paling ringkas menutup dialog adalah form dengan atribut method="dialog" di dalam dialog. Menekan tombol submit di dalamnya tidak mengirim data ke server; browser justru menutup dialog dan menyimpan nilai atribut value tombol yang ditekan ke properti returnValue. Pola ini ideal untuk dialog konfirmasi yang hanya perlu jawaban “ya” atau “batal”.

html Form penutup dialog konfirmasi
<form method="dialog">
  <button value="batal" type="submit">Batal</button>
  <button value="ya" type="submit">Ya, hapus</button>
</form>

Styling ::backdrop #

Saat dialog tampil sebagai modal, browser merender ::backdrop, yaitu area yang menutupi seluruh viewport di belakang dialog. Browser memberi warna latar tipis secara default, dan kita bisa menggantinya dengan selector dialog::backdrop. Latar yang cukup gelap membantu pengunjung menyadari bahwa halaman di belakang sedang tidak aktif.

css Menggelapkan latar di belakang dialog modal
dialog::backdrop {
  background: rgba(15, 23, 42, 0.55);
}

Contoh: Dialog Konfirmasi Hapus #

Kita rakit semuanya menjadi dialog konfirmasi untuk menghapus nota. Tombol “Hapus nota” membuka dialog dengan showModal(), dua tombol di dalam form menutupnya, dan event close membaca returnValue untuk memperbarui teks status.

<!doctype html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Dialog Konfirmasi</title>
  <style>
    body {
      font-family: sans-serif;
      max-width: 480px;
      margin: 24px auto;
      line-height: 1.6;
    }
    dialog {
      border: none;
      border-radius: 8px;
      padding: 20px;
      max-width: 320px;
    }
    dialog::backdrop {
      background: rgba(15, 23, 42, 0.55);
    }
    .aksi {
      display: flex;
      gap: 8px;
      justify-content: flex-end;
      margin-top: 16px;
    }
    button {
      padding: 8px 14px;
      border-radius: 6px;
      border: 1px solid #6b7280;
      background: #f3f4f6;
      cursor: pointer;
    }
    #tombol-ya {
      background: #b3261e;
      color: #ffffff;
      border-color: #b3261e;
    }
  </style>
</head>
<body>
  <h1>Hapus Item</h1>
  <p id="status">Nota #104 masih tersimpan.</p>
  <button id="tombol-hapus" type="button">Hapus nota</button>

  <dialog id="dialog-hapus">
    <p>Hapus nota #104 secara permanen?</p>
    <form method="dialog">
      <div class="aksi">
        <button value="batal" type="submit">Batal</button>
        <button id="tombol-ya" value="ya" type="submit">Ya, hapus</button>
      </div>
    </form>
  </dialog>

  <script>
    const dialog = document.querySelector("#dialog-hapus");
    const tombolHapus = document.querySelector("#tombol-hapus");
    const status = document.querySelector("#status");

    tombolHapus.addEventListener("click", function () {
      dialog.showModal();
    });

    dialog.addEventListener("close", function () {
      if (dialog.returnValue === "ya") {
        status.textContent = "Nota #104 telah dihapus.";
      } else {
        status.textContent = "Penghapusan dibatalkan.";
      }
    });
  </script>
</body>
</html>

Output yang Dihasilkan:

text
Saat halaman baru dibuka:
  - Dialog tidak terlihat; hanya teks status dan tombol "Hapus nota"
Tombol "Hapus nota" ditekan:
  - Dialog tampil di top layer dengan latar halaman menggelap
  - Fokus berpindah ke dalam dialog
Tombol "Batal" ditekan, atau tombol Escape:
  - Dialog tertutup, teks status menjadi "Penghapusan dibatalkan."
Tombol "Ya, hapus" ditekan:
  - Dialog tertutup, teks status menjadi "Nota #104 telah dihapus."

Mari kita bedah isi halaman itu:

  1. Elemen <dialog id="dialog-hapus">: wadah pertanyaan konfirmasi; tidak dirender sampai dibuka lewat method.
  2. Elemen <form method="dialog">: membungkus dua tombol jawaban; submit-nya menutup dialog tanpa mengirim data ke server.
  3. Atribut value pada kedua tombol: menjadi nilai properti returnValue setelah dialog tertutup.
  4. Listener klik #tombol-hapus: memanggil dialog.showModal() sehingga dialog tampil sebagai modal beserta ::backdrop-nya.
  5. Listener event close: berjalan setiap dialog tertutup, termasuk saat ditutup lewat tombol Escape.
  6. Cabang if pada dialog.returnValue: memilih teks status sesuai tombol yang ditekan; Escape tidak menghasilkan nilai “ya”, sehingga alur jatuh ke cabang batal.

Dialog bawaan browser menghemat puluhan baris JavaScript penggantinya, sekaligus memberi pengelolaan fokus yang sulit disamakan. Chapter berikutnya menyorot tombol itu sendiri, yaitu komponen kecil yang memicu seluruh interaksi pada section ini.

Referensi resmi untuk pendalaman:

Berkas Sumber

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

dialog-konfirmasi.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>Dialog Konfirmasi</title>
  <style>
    body {
      font-family: sans-serif;
      max-width: 480px;
      margin: 24px auto;
      line-height: 1.6;
    }
    dialog {
      border: none;
      border-radius: 8px;
      padding: 20px;
      max-width: 320px;
    }
    dialog::backdrop {
      background: rgba(15, 23, 42, 0.55);
    }
    .aksi {
      display: flex;
      gap: 8px;
      justify-content: flex-end;
      margin-top: 16px;
    }
    button {
      padding: 8px 14px;
      border-radius: 6px;
      border: 1px solid #6b7280;
      background: #f3f4f6;
      cursor: pointer;
    }
    #tombol-ya {
      background: #b3261e;
      color: #ffffff;
      border-color: #b3261e;
    }
  </style>
</head>
<body>
  <h1>Hapus Item</h1>
  <p id="status">Nota #104 masih tersimpan.</p>
  <button id="tombol-hapus" type="button">Hapus nota</button>

  <dialog id="dialog-hapus">
    <p>Hapus nota #104 secara permanen?</p>
    <form method="dialog">
      <div class="aksi">
        <button value="batal" type="submit">Batal</button>
        <button id="tombol-ya" value="ya" type="submit">Ya, hapus</button>
      </div>
    </form>
  </dialog>

  <script>
    const dialog = document.querySelector("#dialog-hapus");
    const tombolHapus = document.querySelector("#tombol-hapus");
    const status = document.querySelector("#status");

    tombolHapus.addEventListener("click", function () {
      dialog.showModal();
    });

    dialog.addEventListener("close", function () {
      if (dialog.returnValue === "ya") {
        status.textContent = "Nota #104 telah dihapus.";
      } else {
        status.textContent = "Penghapusan dibatalkan.";
      }
    });
  </script>
</body>
</html>