htmx Tutorial · Common Patterns · Lesson 19 of 30
Delete a Row
Delete items from a table with confirmation and a fade-out, using one hx-confirm for the whole table.
The pattern
- Put
hx-confirmandhx-target="closest tr"on the<tbody>: every delete button inside inherits them. - Each button only needs
hx-delete="/contacts/<id>". hx-swap="outerHTML swap:400ms"and a CSS transition fade the row out.- The server deletes the record and returns an empty 200 response, so the row is replaced by nothing.
<style>tr.htmx-swapping td { opacity: 0; transition: opacity 400ms; }</style>
<table>
<thead><tr><th>Name</th><th></th></tr></thead>
<tbody hx-confirm="Delete this contact?" hx-target="closest tr" hx-swap="outerHTML swap:400ms">
<tr><td>Ada</td><td><button hx-delete="/contacts/1">Delete</button></td></tr>
<tr><td>Grace</td><td><button hx-delete="/contacts/2">Delete</button></td></tr>
<tr><td>Linus</td><td><button hx-delete="/contacts/3">Delete</button></td></tr>
</tbody>
</table>
<!-- The pretend server: on a real site this part is your backend (Python, PHP, Node, Go...) -->
<script>
server.delete("/contacts/:id", () => ""); // 200 with an empty body: the row is replaced by nothing
</script>
Don't use status 204 for this: htmx doesn't swap a 204 response, so the row would stay on the page.
Test yourself
Your delete endpoint returns 204 No Content, and the row doesn't disappear. Why?
htmx doesn't swap 204 responses; return 200 with an empty bodyDELETE requests can't change the pagehx-target must be the button204 responses are cached
Show answer
Answer: htmx doesn't swap 204 responses; return 200 with an empty body
By default, 204 means 'nothing to swap'. An empty 200 replaces the target with nothing.