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>
hx-delete="/order/14": request dengan methodDELETE, yang artinya "hapus data ini".hx-confirm="...": sebelum request dibuat, browser menampilkan dialogconfirm()berisi teks itu, dengan tombol OK dan Batal.hx-target="closest li": target-nya baris<li>terdekat yang memuat tombol. Di tabel, barisnya<tr>, jadiclosest tr.hx-swap="outerHTML": seluruh baris diganti balasan server. Server membalas200dengan body kosong, jadi barisnya hilang.
| 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
- Menghentikan seluruh halaman. Selama dialog terbuka, JavaScript halaman berhenti: jam di papan diam, polling menunggu, animasi membeku. Semuanya baru jalan lagi setelah dialog ditutup.
- Gak bisa dihias. Tampilannya milik browser, tombolnya cuma OK dan Batal dalam bahasa browser. Kamu gak bisa menulis "Ya, hapus" berwarna merah.
- Bisa gak muncul sama sekali. Di iframe ber-
sandboxtanpaallow-modals,confirm()langsung dianggap Batal tanpa tampil, jadi semua tombol Hapus diam.
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>
event.detail.questionberisi tekshx-confirm, ataunulluntuk request tanpahx-confirm(tombol Cek status, polling papan). Tanpa baris pengecekan itu, semua request ikut tertahan.<dialog>denganshowModal()adalah dialog bawaan HTML: ada latar gelap, fokus terkunci di dalamnya, dan tombol Esc menutupnya. Bedanya denganconfirm(), ia bisa dihias dengan CSS, dan halaman tetap jalan selama ia terbuka.<form method="dialog">: tombol yang diklik menutup dialog, danvalue-nya jadidialog.returnValue. Esc menutup denganreturnValuekosong, jadi dianggap batal.issueRequest(true): kirim request yang ditahan.trueartinya lewaticonfirm()bawaan. Tanpatrue, dialog bawaan muncul lagi sesudah dialogmu, jadi kasir ditanya dua kali.
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
- Pertanyaan kosong.
hx-confirm=""gak menanyakan apa pun. Di latihan,<button>harus punyahx-confirmberisi teks,hx-delete="/api/users/1", danhx-target="closest tr". - Server membalas 204. htmx gak menukar apa pun, jadi baris yang sudah dihapus tetap terlihat. Balas 200 kosong. Di latihan, balasan server ditulis sebagai
<template data-url="/api/users/1" data-method="delete"></template>, tanpadata-status, jadi statusnya 200. - Lupa cek
event.detail.question. Handlerhtmx:confirmmenahan semua request, termasuk yang gak perlu ditanya. issueRequest()tanpatrue.confirm()bawaan muncul sesudah dialogmu.
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.