Use when building server-driven UIs with htmx, designing hx-* attribute compositions, choosing swap strategies (innerHTML/outerHTML/morph), wiring out-of-band updates, integrating with form validation, or migrating from a SPA back to server-rendered HTML. Triggers: hx-get/hx-post setup, hx-target + hx-swap interplay, hx-trigger debouncing, OOB swaps for parts of the page outside the request target, response headers like HX-Trigger and HX-Push-Url, integration with Hyperscript or Alpine.js, accessibility considerations on partial updates. NOT for full SPAs (use React/Vue), framework-specific server libraries (use those skills directly), or non-HTML responses.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Use when building server-driven UIs with htmx, designing hx-* attribute compositions, choosing swap strategies (innerHTML/outerHTML/morph), wiring out-of-band updates, integrating with form validation, or migrating from a SPA back to server-rendered HTML. Triggers: hx-get/hx-post setup, hx-target + hx-swap interplay, hx-trigger debouncing, OOB swaps for parts of the page outside the request target, response headers like HX-Trigger and HX-Push-Url, integration with Hyperscript or Alpine.js, accessibility considerations on partial updates. NOT for full SPAs (use React/Vue), framework-specific server libraries (use those skills directly), or non-HTML responses.
metadata
{"category":"Frontend & UI","tags":["htmx","hypermedia","progressive-enhancement","server-rendering","hateoas"],"provenance":{"kind":"first-party","owners":["port-daddy"]},"pairs-with":[{"skill":"hono-patterns","reason":"A lightweight Hono backend returning HTML fragments (branching on the HX-Request header) is the natural server half of an htmx UI"},{"skill":"web-design-expert","reason":"htmx swaps in whatever the server renders; the layout, typography, and interaction design of those fragments live there"},{"skill":"websocket-streaming","reason":"The hx-ext ws/sse extensions ride on server push; connection lifecycle and streaming design come from the paired skill"}],"io-contract":{"kind":"deliverable","consumes":["[Truncated]","[Truncated]"],"produces":["[Truncated]","[Truncated]"]}}
htmx Progressive Enhancement
htmx adds AJAX, CSS transitions, WebSockets, and server-sent events to HTML via attributes. The mental model is "the server returns HTML; the client swaps it in." For most CRUD apps, this beats a SPA in time-to-ship and bundle size.
When to use
Server-rendered app where SPA complexity isn't paying off.
Adding partial updates to a Rails/Django/Laravel/Phoenix/Hono app.
Form-heavy UIs (admin panels, dashboards) without React's overhead.
Migrating away from a SPA that grew past its complexity budget.
Real-time updates via SSE or WebSockets without a frontend framework.
Click → GET /api/widget → response HTML replaces #out content.
Common attributes
Attribute
Purpose
hx-get / hx-post / hx-put / hx-delete / hx-patch
HTTP method + URL.
hx-target
CSS selector for the swap. Default: the element itself. closest, next, previous selectors supported.
hx-swap
How to swap. innerHTML (default), outerHTML, beforebegin, afterbegin, beforeend, afterend, delete, none.
hx-trigger
When to fire. click (default for buttons), change, keyup changed delay:500ms, revealed, every 5s.
hx-include
Extra fields to include with the request.
hx-vals
Static or JS-computed extra params.
hx-confirm
Browser confirm() before request.
hx-indicator
CSS selector to mark "request in flight."
hx-disabled-elt
Disable elements while request runs.
hx-push-url
Update browser URL on success.
Swap strategies
<!-- Replace contents of target --><ahx-get="/feed/items"hx-target="#list"hx-swap="innerHTML">Refresh</a><!-- Replace the target itself --><buttonhx-delete="/items/42"hx-target="closest tr"hx-swap="outerHTML swap:300ms">
Delete
</button><!-- Append to a list (newest at top) --><formhx-post="/comments"hx-target="#comments"hx-swap="afterbegin">
...
</form>
swap:300ms is a CSS transition delay — the old content gets htmx-swapping class for 300ms, you animate it out, then htmx swaps.
The form sends JSON on submit; server echoes HTML back, swapping into the page.
Anti-patterns
Returning JSON when htmx wanted HTML
Symptom: Endpoint returns 200 but nothing changes on the page.
Diagnosis: htmx swaps response bodies as HTML. JSON ends up rendered as text.
Fix: Server returns HTML fragments for htmx requests (detect via HX-Request header). Keep JSON endpoints separate.
Tracking state on the client
Symptom: Race conditions; page shows stale data after multiple actions.
Diagnosis: Trying to maintain client-side state in JS variables.
Fix: Server is the source of truth. Each response includes the new state's HTML. If you're tempted to maintain client state, you probably want a SPA.
Forgotten hx-target for forms
Symptom: Form submission replaces the form's container instead of updating output area.
Diagnosis:hx-target defaults to the element itself; for forms, this is the form.
Fix: Add hx-target="#output" and hx-swap explicitly.
Missing CSRF token
Symptom: POST/PUT/DELETE returns 403 from a framework that enforces CSRF.
Diagnosis: Form helpers usually inject CSRF; htmx requests don't unless you tell them.
Fix: Use hx-headers='{"X-CSRF-Token": "..."}' or include in hx-vals. Some frameworks have htmx-aware CSRF middleware.
No fallback for JS-disabled
Symptom: Site unusable without JS even though it could degrade.
Diagnosis: Forms and links that only work via htmx.
Fix: Use hx-boost="true" on links and forms — without JS they're regular HTML; with JS they upgrade. Combine action="/path" with hx-post="/path" so POST works either way.
Accessibility: focus + announcements
Symptom: Screen reader users don't know content updated.
Diagnosis: Partial swaps don't trigger ARIA live regions automatically.
Fix: Mark dynamic regions with aria-live="polite". Manage focus on swap with hx-on::after-swap. Add visually-hidden announcements for important changes.
Quality gates
htmx request endpoints return HTML, not JSON.
CSRF tokens included on every state-changing request.
Forms work without JS (progressive enhancement, not JS-required).
Dynamic regions have aria-live for screen readers.
Focus managed on swap (hx-on::after-swap).
No client-side state beyond htmx attributes; server is the source of truth.
Loading indicators on every request that takes >300ms.
OOB swaps used for cross-region updates instead of multiple requests.
Trigger debouncing (delay:) on every type-as-you-search input.
Deterministic Audit
Before shipping (or reviewing) an htmx UI, write its shape as a JSON plan matching
schemas/htmx-progressive-enhancement-plan.schema.json and run it through the
deterministic auditor:
auditHtmxProgressiveEnhancement(plan) (in scripts/htmx_progressive_enhancement_audit.mjs)
turns this skill's anti-patterns and Quality Gates into machine-checkable rules over
structured fields — no keyword matching: JSON returned to an htmx swap (the
nothing-happens bug), state-changing requests without a CSRF token, a UI that dies with JS
disabled, dynamic regions with no aria-live, unmanaged focus after swaps, client-side
state stores shadowing the server, undebounced type-ahead search, and multiple requests
where one OOB swap would do. It returns { pass, score, findings, recommendations } and
exits 1 on failure. examples/sample-input.json is a correctly enhanced, accessible plan
(pass: true, zero findings). See CHANGELOG.md for the bundle's history.
NOT for
Full SPAs with rich client state — htmx adds friction for that case.
Framework-specific server-side rendering — use the framework's idioms (Phoenix LiveView, Rails Hotwire, Laravel Livewire are similar but not htmx).
Native mobile — htmx is web-only.
Heavy real-time collaborative apps (Figma-like) — the round-trip cost is too high.