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:

  • this targets the element carrying the attribute
  • closest <selector> walks through ancestors, including the element itself
  • find <selector> finds the first matching descendant
  • next and previous choose a sibling
  • next <selector> and previous <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