HTMX Patterns
OOB helpers, suspense slots, SSE status, nav progress, form a11y — server-driven UI patterns.
Navigation Progress
CSS-only progress bar fixed to the viewport top. Animates automatically when
body.htmx-request is present. Place once in your base layout.
app_shell has its own built-in bar — use nav_progress()
for pages outside the shell.
Preview above (contained). In production it sits at position:fixed; top:0.
OOB Helpers
oob.html provides macros for composing htmx
out-of-band swaps.
Include them in any htmx response to update multiple page regions at once.
oob_fragment
Wrap any content with hx-swap-oob. The swap parameter
defaults to "true" (outerHTML); use "innerHTML" to
replace children only.
This content replaces #my-target via OOB swap.
This replaces the children of #sidebar-stats.
oob_toast
Shorthand for appending a toast notification from any htmx response.
Renders a toast() with oob=true targeting
the toast container.
oob_toast("Item saved!", variant="success")
oob_toast("Something went wrong.", variant="error")
counter_badge
Numeric indicator for navigation items, tabs, and sidebars. Supports
max_count (shows "99+" by default), variant
(warning, danger), and oob=true for server-driven updates.
Hidden automatically when count=0.
Default
5Warning
12Danger
3Overflow (99+)
99+Suspense
Skeleton-to-content swap pattern for deferred loading. The server renders
the shell immediately with skeleton placeholders, then sends deferred
content as OOB swaps targeting each slot's id.
Pairs with Chirp's Suspense(defer_map={}).
suspense_slot (default skeleton)
Renders a generic skeleton placeholder. When the server sends an OOB swap
targeting this id, the skeleton is replaced with real content.
suspense_slot (typed skeleton)
Use skeleton_variant and lines for shaped placeholders.
Card skeleton
Text skeleton (3 lines)
suspense_slot (custom placeholder)
Use call blocks to provide custom loading content.
Loading stats...
suspense_group
Marks a region aria-busy="true" until all child slots resolve.
Assistive tech announces the region as loading; remove aria-busy
when the last slot receives its OOB swap.
SSE Status
Connection status indicators and error recovery for SSE streams.
Pair with streaming_bubble / streaming_block.
sse_status
Dot + label indicator showing connection state. Uses role="status"
and aria-live="polite" for screen readers.
sse_retry
Button that re-fetches an SSE endpoint to reconnect after failure.
Targets the closest [hx-ext] ancestor by default.
Use inside an error state to let users manually recover:
streaming_bubble(role="assistant", streaming=false)
<p>Connection lost.</p>
sse_retry("/api/stream/123")
end
Form Accessibility
Server-rendered form patterns for accessible validation and htmx integration.
form_error_summary
Alert-style box at the top of a form listing all field errors with anchor links.
Renders nothing when there are no errors. Supports oob=true for
partial-page updates.
Empty state (hidden, but present in DOM for OOB targeting):
Safe-by-default forms
The form() macro auto-adds hx-select="unset" and
hx-disinherit="hx-select" when htmx is detected (any hx_post,
hx_put, etc.). This prevents hx-select inherited from
boosted layouts from stripping OOB swaps in form responses.
This form has hx-post, so it automatically gets
hx-select="unset", hx-sync="this:drop", and disabled submit
controls while the request is in flight. Explicit hx_select,
hx_sync, and hx_disabled_elt override the defaults.
Per-field OOB
Each field has id="field-{name}" and an error container
id="errors-{name}" with role="alert".
Set oob=true on field_wrapper to swap individual
fields without re-rendering the whole form.
The error container (#errors-username) is always in the DOM.
Server returns just the field with oob=true to update it in-place.