Targets and swaps

Insert before or after existing content

Append, prepend, or place a returned fragment next to the target without rerendering the entire list.

Adjacent swaps use the same positions as insertAdjacentHTML. They let you insert a fragment without rerendering the whole list.

  • beforebegin: before the target itself
  • afterbegin: inside the target, before its first child
  • beforeend: inside the target, after its last child
  • afterend: after the target itself

To append a newly created task:

<form action="/tasks" method="post"
  hx-post="/tasks"
  hx-target="#task-list"
  hx-swap="beforeend">
  ...
</form>

<ul id="task-list"></ul>

The server returns one valid <li>. The list remains and the new row is inserted at its end. Existing rows keep their scroll position and any local state, which is nicer than replacing the whole <ul> for a single addition.

Appending is correct only when the new row is the complete change. If creation also changes sorting, a total, pagination, or an empty-state message, returning the whole list region is simpler and less prone to stale UI. I start with beforeend for quick prototypes, then switch to a full list refresh when the screen gains totals or sort order.

Also consider concurrent requests. Two responses may arrive in a different order than they were sent. If order matters, synchronize the requests with hx-sync or let the server return the complete authoritative ordering. Appending two rows that should be sorted alphabetically is a common place this shows up.

afterbegin is useful when the newest item should appear at the top of a feed. The server still returns one complete row or card. Only the insertion point changes.

Try this on your own project: create two tasks quickly and confirm the list order matches what your server intended.

Lesson completed