Konfirmasi dan Dialog — HTMX

HTMX menyediakan hx-confirm untuk konfirmasi sebelum request. hx-confirm Hapus User Browser menampilkan dialog confirm() bawaan. Jika user klik Cancel…

hx-confirm membuat htmx bertanya dulu sebelum mengirim request, dan request-nya cuma dikirim kalau pengguna setuju. Bayangin Bu Rini sebelum mencoret order dari buku. Dia bertanya ke kasir, "Yakin hapus order #14 Mas Yoga?". Kalau kasir bilang batal, buku gak disentuh sama sekali. Coretan di buku itu request DELETE, dan pertanyaan Bu Rini itu hx-confirm.

🧪 Tebakan cepat: Tombol Hapus di baris #14 punya hx-confirm="Hapus order #14 Mas Yoga?". Kasir mengkliknya, lalu menekan Batal di dialog. Berapa request yang sampai ke server? Jawabannya ada di bagian "hx-confirm: tanya dulu, baru kirim".

hx-confirm: tanya dulu, baru kirim

<li id="order-14">#14 Mas Yoga, 5 kg: <span>Siap diambil</span>
  <button hx-delete="/order/14"
          hx-confirm="Hapus order #14 Mas Yoga?"
          hx-target="closest li"
          hx-swap="outerHTML">Hapus</button>
</li>
Kasir menekan Request Baris #14
OK DELETE /order/14, dibalas 200 kosong hilang
Batal gak ada tetap

Batal berarti request gak pernah dibuat: 0 request, dan server gak tahu apa-apa. Itu jawaban tebakannya.

Balasan 204 membuat baris gak hilang

Di Laravel, response()->noContent() membalas status 204 No Content. htmx 2 sengaja gak menukar apa pun untuk 204. Ordernya sudah terhapus di database, tapi barisnya tetap terlihat di papan. Untuk menghapus baris, balas 200 dengan body kosong: return response('', 200);.

Kenapa confirm() bawaan kurang enak

Dialog sendiri: htmx:confirm dan dialog

Sebelum setiap request, htmx mengirim event htmx:confirm. Kalau event itu ditahan dengan preventDefault(), request-nya menunggu sampai kamu memanggil event.detail.issueRequest(true):

<dialog id="tanya-hapus">
  <p id="tanya-teks"></p>
  <form method="dialog">
    <button value="batal">Batal</button>
    <button value="ya">Ya, hapus</button>
  </form>
</dialog>

<script>
  document.body.addEventListener('htmx:confirm', (event) => {
    if (!event.detail.question) return  // request tanpa hx-confirm jalan biasa
    event.preventDefault()               // tahan request-nya
    const dialog = document.getElementById('tanya-hapus')
    document.getElementById('tanya-teks').textContent = event.detail.question
    dialog.returnValue = ''
    dialog.showModal()
    dialog.addEventListener('close', () => {
      if (dialog.returnValue === 'ya') event.detail.issueRequest(true)
    }, { once: true })
  })
</script>

hx-confirm ikut diwariskan

hx-confirm berlaku untuk elemen itu dan semua isinya. Kalau ditulis di <ul id="papan-order">, tombol Cek status di dalamnya ikut bertanya "Hapus order?". Tulis di tombol yang menghapus saja.

⚠️ Jebakan yang sering ketemu

TL;DR: hx-confirm="Hapus order #14 Mas Yoga?" menampilkan confirm() sebelum request. OK mengirimnya, Batal membatalkannya: request gak pernah dibuat. Dengan hx-delete, hx-target="closest li" (di tabel closest tr), dan hx-swap="outerHTML", balasan 200 kosong menghapus barisnya, sedangkan 204 gak menukar apa pun. confirm() menghentikan halaman, gak bisa dihias, dan bisa gak muncul di iframe ber-sandbox. Dialog sendiri: dengarkan htmx:confirm, lewati request tanpa event.detail.question, preventDefault(), tampilkan <dialog> dengan showModal(), lalu panggil event.detail.issueRequest(true) kalau jawabannya ya. hx-confirm diwariskan ke semua isi elemennya.

Yang akan kamu pelajari