Documentation
¶
Overview ¶
Package htmx provides HTMX integration helpers including error handling patterns and response utilities for building dynamic web applications.
The tc-btn-loading indicator hook ¶
LoadingButton wraps its output in a `<span class="tc-btn-loading">`. That class is a deliberately public, stable hook for hx-indicator scoping: by default HTMX toggles `.htmx-indicator` visibility relative to the REQUESTING element, but when the request fires from a different element (e.g. a form submit driving a toolbar button), point hx-indicator at the wrapper:
<button hx-post="/save" hx-indicator="closest .tc-btn-loading">
@htmx.LoadingButton("Save", "Saving…", spinner)
</button>
Do not remove or rename the class — consumer CSS and hx-indicator selectors depend on it (guarded by htmx snapshot tests + the demo's visualtest/loading_button_e2e_test.go).
Index ¶
- func CSRFToken(token string) templ.Component
- func ConfirmDelete(props ConfirmDeleteProps) templ.Component
- func GlobalErrorHandling(cfg ErrorHandlingConfig) templ.Component
- func InlineLoadingOverlay(id string, spinner templ.Component) templ.Component
- func LoadingButton(defaultText, loadingText string, spinner templ.Component) templ.Component
- func LoadingIndicator(spinner templ.Component) templ.Component
- func PolledLiveIsValid(v PolledLive) bool
- func PolledRegion(props PolledRegionProps) templ.Component
- func SwapOOB(props SwapOOBProps) templ.Component
- func SwapStyleIsValid(v SwapStyle) bool
- func ViewTransitions(props ViewTransitionsProps) templ.Component
- type ConfirmDeleteProps
- type ErrorHandlingConfig
- type PolledLive
- type PolledRegionProps
- type SwapOOBProps
- type SwapStyle
- type ViewTransitionsProps
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CSRFToken ¶
CSRFToken renders a hidden input for HTMX forms with CSRF protection
@htmx.CSRFToken("csrf_token_value")
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.CSRFToken("csrf-token")
}
Output:
func ConfirmDelete ¶
func ConfirmDelete(props ConfirmDeleteProps) templ.Component
ConfirmDelete renders a button with a confirmation dialog for destructive actions. HTMX-ONLY by design: the pinned Datastar runtime ships NO confirm machinery (bundle-verified 2026-10-03 — zero confirm tokens in the v0.6.1 bundle), so there is no wire-dialect twin. A Datastar caller that needs confirmation owns it consumer-side (e.g. a data-on:click__prevent handler that re-fires the action after its own dialog resolves).
@htmx.ConfirmDelete(htmx.ConfirmDeleteProps{Delete: "/delete/123", Target: "#item-123", Confirm: "Are you sure?"})
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.ConfirmDelete(htmx.ConfirmDeleteProps{Delete: "/items/1", Target: "#list"})
}
Output:
func GlobalErrorHandling ¶
func GlobalErrorHandling(cfg ErrorHandlingConfig) templ.Component
GlobalErrorHandling renders a comprehensive global HTMX error handling script. Include this once in your base layout, ideally at the end of the body. Requires feedback.ToastContainer on the page for accessible error announcements (aria-live). If ToastContainer is not present, errors are only logged to the console.
Typical layout wiring:
@layout.Base(layout.PageProps{...}) {
@feedback.ToastContainer(nonce) // must be present for toast error feedback
// ... page content ...
@htmx.GlobalErrorHandling(htmx.DefaultErrorHandlingConfig())
}
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.GlobalErrorHandling(htmx.DefaultErrorHandlingConfig())
}
Output:
func InlineLoadingOverlay ¶
InlineLoadingOverlay renders a localized loading overlay for HTMX targets. Accepts a spinner component for decoupled loading animation.
@htmx.InlineLoadingOverlay("tc-form-loading", feedback.Spinner(feedback.SpinnerProps{Size: feedback.SpinnerMD, Color: "text-blue-600 dark:text-blue-400"}))
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.InlineLoadingOverlay("results", nil)
}
Output:
func LoadingButton ¶
LoadingButton renders a button with built-in loading state. During an HTMX request (htmx-request on the button or an ancestor) the default text hides and the loading text + spinner show; at rest only the default text is visible. The spinner is wrapped in htmx-indicator so it is gated regardless of the color classes passed in. The tc-btn-loading wrapper is a stable hook for hx-indicator when a different indicator scope is needed.
<button class="btn-primary" hx-post="/save">
@htmx.LoadingButton("Save", "Saving...", feedback.Spinner(feedback.SpinnerProps{Size: feedback.SpinnerSM, Color: "text-white"}))
</button>
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.LoadingButton("Save", "Saving...", nil)
}
Output:
func LoadingIndicator ¶
LoadingIndicator renders a fixed-position HTMX loading indicator. Accepts a spinner component for decoupled loading animation.
@htmx.LoadingIndicator(feedback.Spinner(feedback.SpinnerProps{Size: feedback.SpinnerLG, Color: "text-blue-600 dark:text-blue-400"}))
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.LoadingIndicator(nil)
}
Output:
func PolledLiveIsValid ¶
func PolledLiveIsValid(v PolledLive) bool
PolledLiveIsValid reports whether v is one of the defined PolledLive constants.
func PolledRegion ¶
func PolledRegion(props PolledRegionProps) templ.Component
PolledRegion renders a div that auto-refreshes its content via HTMX polling on an interval. The region replaces itself (hx-swap="outerHTML") on each poll, which means the children re-render server-side on every request.
Include a "Updated HH:MM:SS" timestamp (ShowTimestamp: true) so operators can verify polling is active — if the timestamp freezes, polling has stalled.
When Eager is set, the region renders with an aria-busy="true" busy cue (data-tc-polled-busy marker) and a singleton script that fires the first fetch once per initial-DOM region on DOMContentLoaded, then clears the busy cue on the first completed request (htmx:afterSwap covers successful self-replacement, htmx:afterRequest covers error completions) — parity with datastar.LiveRegion's busy cue, so screen readers wait for the fresh content instead of announcing the stale initial render twice.
EAGER NEVER EMITS AN hx-trigger "load" TOKEN. With the default hx-swap="outerHTML" the region replaces ITSELF on every response; htmx processes each swapped-in element and fires "load" again, so hx-trigger="load, every Ns" on a self-replacing element is an infinite self-refetch loop (the 2026-09-04 DiscordSync projection-health outage). The eager fetch is therefore issued by the script as a one-shot htmx.ajax call. Regions injected after the initial page load (htmx partial swaps, boosted navigation) get no eager fetch and degrade to interval-only polling — the busy cue clears on their first interval response.
@htmx.PolledRegion(htmx.PolledRegionProps{URL: "/partials/stats", Every: "10s", Eager: true}) {
@display.StatCard(display.StatCardProps{Label: "Messages", Value: "1,234"})
}
HYBRID RENDERING CAVEAT (strings.Builder path): PolledRegion is a children-slot component — rendered outside a templ file (component.Render straight into a strings.Builder) the { children... } slot renders EMPTY, and an empty polled region swaps itself for the endpoint's response on the first tick anyway. Render PolledRegion from a real templ file whose children are the server-side partial (the poll endpoint should serve that same partial), or pass children programmatically via templ.WithChildren(ctx, child) before Render. See docs/recipes/hybrid-strings-builder-rendering.md.
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.PolledRegion(htmx.DefaultPolledRegionProps())
}
Output:
func SwapOOB ¶
func SwapOOB(props SwapOOBProps) templ.Component
SwapOOB renders an out-of-band swap wrapper for HTMX responses. Use this to update multiple elements in a single response. Invalid swap styles fall back to outerHTML.
@htmx.SwapOOB(htmx.SwapOOBProps{Selector: "#toast-container", SwapStyle: htmx.SwapBeforeEnd}) {
@feedback.Toast(props)
}
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.SwapOOB(htmx.SwapOOBProps{Selector: "#list"})
}
Output:
func SwapStyleIsValid ¶
SwapStyleIsValid reports whether v is one of the defined SwapStyle constants.
func ViewTransitions ¶
func ViewTransitions(props ViewTransitionsProps) templ.Component
ViewTransitions renders a CSP-safe script that enables native View Transitions for HTMX swaps, plus default transition CSS.
Place this component once per page, typically in the <head> or at the end of <body> before other HTMX-using components.
@htmx.ViewTransitions(htmx.ViewTransitionsProps{Global: true})
Example ¶
package main
import (
"github.com/larsartmann/templ-components/htmx"
)
func main() {
_ = htmx.ViewTransitions(htmx.DefaultViewTransitionsProps())
}
Output:
Types ¶
type ConfirmDeleteProps ¶
ConfirmDeleteProps configures a confirmation delete button.
type ErrorHandlingConfig ¶
type ErrorHandlingConfig struct {
// Nonce is the CSP nonce for inline scripts
Nonce string
// MaxErrorHistory is the maximum number of errors to track (default: 10)
MaxErrorHistory int
// MaxRetries is the maximum number of retry attempts for server errors (default: 2)
MaxRetries int
// RetryDelayMS is the base delay in milliseconds between retries, multiplied by retry count (default: 1000)
RetryDelayMS int
}
ErrorHandlingConfig configures the global HTMX error handling behavior
func DefaultErrorHandlingConfig ¶
func DefaultErrorHandlingConfig() ErrorHandlingConfig
DefaultErrorHandlingConfig returns sensible defaults for error handling
type PolledLive ¶
type PolledLive string
PolledLive is the aria-live politeness setting for a polled region.
const ( // PolledLivePolite announces updates after the current speech finishes (default). PolledLivePolite PolledLive = "polite" // PolledLiveAssertive announces updates immediately, interrupting current speech. PolledLiveAssertive PolledLive = "assertive" // PolledLiveOff disables screen-reader announcements for this region. PolledLiveOff PolledLive = "off" )
type PolledRegionProps ¶
type PolledRegionProps struct {
utils.BaseProps
// URL is the HTMX endpoint to fetch for refreshing the region content.
URL string
// Every is the poll interval as an HTMX timing string (e.g. "10s", "2m", "500ms").
Every string
// Eager fires the first fetch immediately on page load in addition to
// polling. When false, the first fetch happens after the first interval
// elapses. Ignored when Trigger is set.
//
// Eager never emits an hx-trigger "load" token: with the default
// hx-swap="outerHTML" the region replaces itself on every response and
// htmx re-fires "load" for each swapped-in element, which is an
// infinite self-refetch loop. Instead the busy-cue script issues one
// htmx.ajax call per initial-DOM region on DOMContentLoaded. Regions
// injected after the initial page load degrade to interval-only
// polling.
Eager bool
// Trigger overrides the auto-generated hx-trigger value. When set,
// Every and Eager are ignored and this string is used verbatim as
// hx-trigger. Useful for custom triggers like SSE events
// (e.g. "stats-refresh from:body").
Trigger string
// Swap controls how the fetched content replaces the region.
// Defaults to SwapOuterHTML.
Swap SwapStyle
// Live sets the aria-live politeness for screen-reader announcements.
// Defaults to PolledLivePolite.
Live PolledLive
// ShowTimestamp renders a "Updated HH:MM:SS" footer so operators can see
// at a glance that polling is active (the timestamp ticks forward on each
// successful poll because the whole region re-renders).
ShowTimestamp bool
// Now overrides the wall clock used for the timestamp footer. Nil (the
// zero default) means time.Now. Inject a fixed clock in visual goldens
// and tests so ShowTimestamp coverage is deterministic instead of
// flaking across the second boundary (or being disabled outright).
Now func() time.Time
// TimeFormat is the Go time format string for the timestamp footer.
// Default: "15:04:05" (time-only). Use time.RFC3339 for full date+time.
TimeFormat string
}
PolledRegionProps configures an auto-refreshing HTMX region.
func DefaultPolledRegionProps ¶
func DefaultPolledRegionProps() PolledRegionProps
DefaultPolledRegionProps returns sensible defaults for a polled region.
type SwapOOBProps ¶
SwapOOBProps configures an out-of-band swap wrapper.
type SwapStyle ¶
type SwapStyle string
SwapStyle is an HTMX swap style for out-of-band updates.
const ( SwapInnerHTML SwapStyle = "innerHTML" SwapOuterHTML SwapStyle = "outerHTML" SwapBeforeBegin SwapStyle = "beforebegin" SwapAfterBegin SwapStyle = "afterbegin" SwapBeforeEnd SwapStyle = "beforeend" SwapAfterEnd SwapStyle = "afterend" SwapDelete SwapStyle = "delete" SwapNone SwapStyle = "none" )
HTMX swap styles (https://htmx.org/attributes/hx-swap/).
type ViewTransitionsProps ¶
type ViewTransitionsProps struct {
utils.BaseProps
// Global enables View Transitions for ALL HTMX swaps on the page.
// When false, consumers opt in per-element via hx-swap="... transition:true".
Global bool
}
ViewTransitionsProps configures native View Transitions API integration for HTMX content swaps.
The View Transitions API provides smooth, animated transitions between DOM states — cross-fades, shared-element morphing, and custom animations — with zero JavaScript beyond enabling the feature.
HTMX 2.0 supports View Transitions natively. This component:
- Optionally enables View Transitions globally for all HTMX swaps
- Renders CSS for default and customizable transition animations
Graceful degradation: browsers without View Transitions support (older Firefox/Safari) perform instant swaps — identical to current behavior.
func DefaultViewTransitionsProps ¶
func DefaultViewTransitionsProps() ViewTransitionsProps
DefaultViewTransitionsProps returns sensible defaults.