Targets and swaps
Use relative targets
Build reusable controls with this, closest, find, next, and previous instead of unique ids for every row.
Relative targets let repeated components describe their local structure without generating a unique global ID for every row. That matters on lists where each row has the same actions.
<li>
<span>Send invoice</span>
<button
hx-delete="/tasks/42"
hx-target="closest li"
hx-swap="delete">
Delete
</button>
</li>
HTMX supports several extended selectors:
thistargets the element carrying the attributeclosest <selector>walks through ancestors, including the element itselffind <selector>finds the first matching descendantnextandpreviouschoose a siblingnext <selector>andprevious <selector>scan forward or backward
The selector is resolved from the triggering element, including when an inherited attribute was declared on a parent. That detail matters for find: the trigger’s descendants may differ from the parent’s descendants. If a parent sets hx-target="find .status" and a child button fires the request, HTMX searches inside the button, not inside the whole parent card.
Use relative selectors for a stable component relationship such as “this row” or “the next error message.” Use an ID when the target is a page-level region unrelated to the trigger’s local tree. The task list container is #task-list. The row to delete is closest li.
Duplicate the row in your template and confirm both buttons update only their own copy. That two-row test catches inherited-target mistakes faster than reading markup alone.
hx-swap="delete" pairs naturally with hx-target="closest li". The row removes itself after a successful delete response, even when the response body is empty.
Try this on your own project: replace one row-specific ID target with closest li or find .message and verify both rows still behave independently.
Lesson completed