Step 2 — Add an htmx interaction

Wire a button to swap a fragment without reloading the page.

Make a button talk to the server

Thebtn macro accepts an hxdict, so a single call describes the whole request: where it posts, what it targets, and how the response is swapped.

{% from "chirpui/button.html" import btn %}

{{ btn("Refresh", hx={"get": "/widgets/latest", "target": "#widget", "swap": "innerHTML"}) }}

<div id="widget">
  {% include "partials/widget.html" %}
</div>

What happens on click

htmx issues the request, the server returns just the widget fragment, and htmx swaps it into#widget. The rest of the page — scroll position, focus, any Alpine state — is untouched. No full reload, no client framework.

That is the whole loop: render HTML on the server, target a region, swap the response. From here you can layer in forms, out-of-band updates, and server-sent events using the same attribute vocabulary.