Use templ with htmx
Two ways to do partial updates: the generic hx-* pattern (works with any server) and templ’s native fragment rendering.
Pattern 1: hx-* attributes
htmx posts a request and swaps in whatever the server returns. The trick: give the element an id and use hx-select so htmx extracts the matching piece from the full page the server sends back.
<form id="countsForm"
hx-post="/"
hx-select="#countsForm"
hx-swap="outerHTML">
<!-- inputs -->
</form>
The server just renders the full page - it does not need to know htmx exists. htmx receives the whole document and keeps only the selected element. Inline handlers via hx-on:* attributes are supported in templ markup too.
This pattern is simple but sends more bytes than necessary. Native fragments fix that.
Pattern 2: native fragments
Mark a subtree with templ.Fragment, then tell the handler which fragments to serve:
templ countsForm(n int) {
@templ.Fragment("countsForm") {
<form id="countsForm">
<output>{ fmt.Sprint(n) }</output>
</form>
}
}
templ page(n int) {
@layout(countsForm(n))
}
mux.Handle("POST /counts", templ.Handler(page(n), templ.WithFragments("countsForm")))
templ.WithFragments (handler.go) makes the templ.Fragment markers addressable (fragment.go). Requests carrying the fragment id get just that subtree.
What happens on a fragment request:
- The full page renders into a buffer first; only the fragment is emitted
- Because output is buffered, an error mid-render produces no partial HTML on the wire
- Non-fragment requests fall through to the normal response
Gotcha: A fragment request returns the whole page if the server forgot
templ.WithFragments. Both halves must agree: the handler option and the fragment id in the request.
Which to use
Start with fragments when you control both ends - fewer bytes, explicit boundaries. Use hx-select when the same endpoint also serves non-htmx clients and you do not want a second code path.
For the client-side half (attributes, swaps, triggers, events), see the lab’s htmx topic.