kj-confirm="Delete invoice #1001?" shows the browser's native confirm dialog and cancels the request if the user declines. kj-indicator="#spinner" shows the named element for the duration of the request and hides it afterwards.
While a request is in flight the element carries aria-busy="true", which assistive technology understands and which you can style: [aria-busy="true"] { opacity: .6; cursor: progress; }.
| Invoice | Amount | Actions |
|---|---|---|
| #1001 | $420 | |
| #1002 | $1,280 | |
| #1003 | $96 |
Zero JavaScript. items.php answers DELETE with an empty body, so outerHTML removes the row.
View the source for this demo
<div class="table-wrap" style="margin-top:0"><table class="inv">
<thead><tr><th scope="col">Invoice</th><th scope="col">Amount</th><th scope="col"><span class="sr-only">Actions</span></th></tr></thead>
<tbody>
<tr id="inv-1"><td>#1001</td><td>$420</td><td><button type="button" kj-delete="/api/items.php?id=1" kj-target="#inv-1" kj-swap="outerHTML" kj-confirm="Delete invoice #1001?">Delete</button></td></tr>
<tr id="inv-2"><td>#1002</td><td>$1,280</td><td><button type="button" kj-delete="/api/items.php?id=2" kj-target="#inv-2" kj-swap="outerHTML" kj-confirm="Delete invoice #1002?">Delete</button></td></tr>
<tr id="inv-3"><td>#1003</td><td>$96</td><td><button type="button" kj-delete="/api/items.php?id=3" kj-target="#inv-3" kj-swap="outerHTML" kj-confirm="Delete invoice #1003?">Delete</button></td></tr>
</tbody>
</table></div>
<div class="row" style="margin-top:14px">
<button type="button" kj-get="/api/slow.php?ms=1600" kj-target="#report" kj-indicator="#report-spin">Run report (1.6 s)</button>
<div class="spin" id="report-spin" role="status">Working…</div>
</div>
<div id="report" aria-live="polite" style="margin-top:10px"></div>More examples
Markup
<button kj-delete="/api/account" kj-confirm="This cannot be undone. Continue?">Delete account</button>
<button kj-post="/export" kj-indicator="#export-spin">Export CSV</button>
<span id="export-spin" hidden>Preparing…</span>API
Element to show while the request is in flight (the trigger also gets aria-busy="true").
Migrating
hx-confirm → kj-confirm. jsKjs shows/hides the indicator element itself rather than toggling an htmx-request class; hx-disabled-elt is not included.Related features
Declarative requests
Make GET, POST, PUT, PATCH and DELETE requests straight from HTML with kj-get, kj-post and friends — htmx-style hypermedia with zero JavaScript.
Open →HyperRequest lifecycle events
Every declarative request emits bubbling lifecycle events — kj:before, kj:after, kj:error and kj:load — so one document-level listener can drive a page-wide progress bar or error toast..
Open →HyperTargets & swaps
Control exactly where server HTML lands with kj-target and how it is inserted with kj-swap — innerHTML, outerHTML, beforebegin, afterbegin, beforeend, afterend, textContent or none..
Open →