CtrlK
BlogDocsLog inGet started
Tessl Logo

alonso-skills/htmx

Implements HTMX interactions, configures swap behaviors, debugs hx-* requests, and builds hypermedia-driven UI components. Use when tasks involve hx-* attributes, HTMX AJAX requests, swap strategies, server-sent events, WebSockets, or hypermedia-driven UIs.

95

Quality

95%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

attributes.mdreferences/

description:
Complete reference for all HTMX attributes.
globs:
*.html

HTMX Attributes

All hx-* attributes, their accepted values, modifiers, and behavior.

Note: All hx-* attributes can also be written as data-hx-* for HTML validation compliance (e.g., data-hx-get, data-hx-trigger).

Contents

  • Core Request Attributes
  • Trigger Attribute
  • Target & Swap Attributes
  • Value & Parameter Attributes
  • History Attributes
  • UI Feedback Attributes
  • Inheritance Control
  • Security Attributes
  • Miscellaneous Attributes

Core Request Attributes

These attributes issue HTTP requests when the element is triggered.

<!-- GET request -->
<button hx-get="/api/items">Load Items</button>

<!-- POST request -->
<form hx-post="/api/items">
    <input name="title" />
    <button type="submit">Create</button>
</form>

<!-- PUT request -->
<button hx-put="/api/items/1">Update</button>

<!-- PATCH request -->
<button hx-patch="/api/items/1">Patch</button>

<!-- DELETE request -->
<button hx-delete="/api/items/1">Delete</button>
AttributeHTTP MethodNotes
hx-getGETParameters appended to URL as query string
hx-postPOSTParameters sent in request body
hx-putPUTParameters sent in request body
hx-patchPATCHParameters sent in request body
hx-deleteDELETEParameters appended to URL by default

Value: A URL string (relative or absolute). Relative URLs resolve against the current page.

Trigger Attribute

hx-trigger specifies which event(s) cause the request to fire.

Important: hx-trigger is NOT inherited. It must be set on each element individually.

Default Triggers (when hx-trigger is omitted)

Element TypeDefault Event
<input>, <textarea>, <select>change
<form>submit
Everything elseclick

Syntax

<!-- Single event -->
<div hx-get="/data" hx-trigger="click">Click me</div>

<!-- Multiple events (comma-separated) -->
<div hx-get="/data" hx-trigger="click, keyup">Either works</div>

<!-- Event with modifiers -->
<input hx-get="/search" hx-trigger="keyup changed delay:500ms" />

<!-- Event with filter -->
<div hx-get="/data" hx-trigger="click[ctrlKey]">Ctrl+Click only</div>

<!-- Event from another element -->
<div hx-get="/data" hx-trigger="click from:body">Body click</div>

<!-- Polling -->
<div hx-get="/status" hx-trigger="every 2s">Status: loading...</div>

<!-- Intersection observer -->
<img hx-get="/image" hx-trigger="intersect threshold:0.5" />

Trigger Modifiers

ModifierEffect
onceTrigger only fires once
changedOnly fire if the element's value has changed
delay:<time>Wait before issuing request; resets if event fires again (debounce)
throttle:<time>Wait before issuing request; discard events during wait (throttle)
from:<CSS selector>Listen for event on a different element. Also accepts document, window, closest <selector>, find <selector>, next, next <selector>, previous, previous <selector>. Note: Selectors with whitespace require parentheses: from:(form input)
target:<CSS selector>Only fire if the event target matches the selector
consumePrevent event from propagating to parent elements
queue:<strategy>Queue behavior when event fires during an active request. Values: first, last (default), all, none

Trigger Filters

JavaScript expressions inside square brackets. The event object is available as event. Standard event properties work: ctrlKey, shiftKey, altKey, metaKey, key, etc.

<!-- Only on Ctrl+Click -->
<div hx-get="/data" hx-trigger="click[ctrlKey]">Ctrl+Click</div>

<!-- Only on Enter key -->
<input hx-get="/search" hx-trigger="keyup[key=='Enter']" />

<!-- Custom condition -->
<div hx-get="/data" hx-trigger="click[checkCondition()]">Conditional</div>

Special Triggers

TriggerWhen It Fires
loadWhen the element is loaded into the DOM
revealedWhen the element first scrolls into the viewport
intersectWhen the element intersects the viewport. Options: root:<selector>, threshold:<float>
every <time>Polls at the given interval (e.g., every 2s, every 500ms)

Stopping polling: The server responds with HTTP status 286 to signal the client to stop polling.

Load Polling

Combine load trigger with delay for server-driven polling:

<div hx-get="/status" hx-trigger="load delay:1s" hx-swap="outerHTML">
    Checking status...
</div>

The server returns a new element with the same trigger to continue, or without it to stop.

Target & Swap Attributes

hx-target

Specifies which element receives the response content.

<!-- CSS selector -->
<button hx-get="/data" hx-target="#results">Load</button>

<!-- this (current element) -->
<button hx-get="/data" hx-target="this">Replace me</button>

<!-- Extended selectors -->
<button hx-get="/data" hx-target="closest div">Nearest div ancestor</button>
<button hx-get="/data" hx-target="find .content">First .content descendant</button>
<button hx-get="/data" hx-target="next .sibling">Next .sibling in DOM</button>
<button hx-get="/data" hx-target="previous .sibling">Previous .sibling in DOM</button>
Extended SelectorMeaning
thisThe element itself
closest <selector>Nearest ancestor matching selector
find <selector>First descendant matching selector
nextNext sibling element
next <selector>Next element in DOM matching selector
previousPrevious sibling element
previous <selector>Previous element in DOM matching selector

Default: Without hx-target, the element that made the request is the target.

hx-swap

Controls how the response content is inserted into the target. See references/swapping.md for full details.

Values: innerHTML (default), outerHTML, textContent, beforebegin, afterbegin, beforeend, afterend, delete, none

hx-select

Pick a subset of the response to swap in using a CSS selector.

<!-- Only swap in the #results element from the response -->
<button hx-get="/page" hx-select="#results" hx-target="#results">Load</button>

hx-select-oob

Pick specific elements from the response for out-of-band swaps.

<!-- Swap #results into target, and also OOB swap #notification -->
<button hx-get="/page" hx-select="#results" hx-select-oob="#notification">Load</button>

Value & Parameter Attributes

hx-vals

Add extra values to the request as a JSON object.

<!-- Static JSON values -->
<button hx-post="/action" hx-vals='{"key": "value", "count": 42}'>Submit</button>

<!-- Dynamic values with js: prefix -->
<button hx-post="/action" hx-vals='js:{timestamp: Date.now()}'>Submit</button>

hx-vars (deprecated — use hx-vals with js: prefix)

Comma-separated name-expression pairs evaluated as JavaScript.

hx-include

Include values from additional elements in the request.

<!-- Include specific input -->
<button hx-post="/action" hx-include="#extra-field">Submit</button>

<!-- Include all inputs in a container -->
<button hx-post="/action" hx-include="#sidebar">Submit</button>

<!-- Extended selectors work -->
<button hx-post="/action" hx-include="closest form">Submit</button>

hx-params

Filter which parameters are submitted.

<!-- Only include listed params -->
<form hx-post="/action" hx-params="name, email">...</form>

<!-- Exclude listed params -->
<form hx-post="/action" hx-params="not password">...</form>

<!-- Include all (default) -->
<form hx-post="/action" hx-params="*">...</form>

<!-- Include none -->
<form hx-post="/action" hx-params="none">...</form>

hx-encoding

Set the encoding type for the request.

<!-- Required for file uploads -->
<form hx-post="/upload" hx-encoding="multipart/form-data">
    <input type="file" name="document" />
    <button type="submit">Upload</button>
</form>

hx-headers

Add custom headers to the request as a JSON object.

<!-- Static headers -->
<div hx-get="/api" hx-headers='{"X-Custom": "value"}'>Load</div>

<!-- Dynamic headers with js: prefix -->
<div hx-get="/api" hx-headers='js:{"Authorization": "Bearer " + getToken()}'>Load</div>

History Attributes

hx-push-url

Push a URL into the browser's history stack after a successful request.

<!-- Push the request URL -->
<a hx-get="/page" hx-push-url="true">Navigate</a>

<!-- Push a custom URL -->
<a hx-get="/api/page" hx-push-url="/page">Navigate</a>

<!-- Disable (override inherited) -->
<a hx-get="/page" hx-push-url="false">No history</a>

hx-replace-url

Replace the current URL in the browser's location bar (no new history entry).

<a hx-get="/page" hx-replace-url="true">Update URL</a>
<a hx-get="/api/page" hx-replace-url="/page">Custom URL</a>

hx-history

Prevent the current page from being saved in the history cache.

<!-- On the page's body or a top-level element -->
<body hx-history="false">
    <!-- Sensitive content not cached -->
</body>

hx-history-elt

Specify which element should be snapshot and restored during history navigation (default: <body>). This element must always be visible in the application for proper history restoration. Not inherited.

<div id="content" hx-history-elt>
    <!-- Only this element is cached/restored -->
</div>

UI Feedback Attributes

hx-indicator

Specify the element that gets the htmx-request class during requests, making indicators visible.

<button hx-get="/data" hx-indicator="#spinner">
    Load
</button>
<span id="spinner" class="htmx-indicator">Loading...</span>

The htmx-indicator class sets opacity: 0 by default. When the parent (or hx-indicator target) receives htmx-request, the indicator becomes visible (opacity: 1).

Multiple indicators:

<button hx-get="/data" hx-indicator=".my-indicator">Load</button>

hx-disabled-elt

Add the disabled attribute to elements while a request is in flight.

<!-- Disable this element -->
<button hx-post="/action" hx-disabled-elt="this">Submit</button>

<!-- Disable another element -->
<button hx-post="/action" hx-disabled-elt="#other-btn">Submit</button>

<!-- Disable multiple elements -->
<button hx-post="/action" hx-disabled-elt="closest form, #other-btn">Submit</button>

hx-confirm

Show a browser confirm() dialog before issuing the request.

<button hx-delete="/item/1" hx-confirm="Are you sure?">Delete</button>

Use hx-confirm="unset" on a child to disable an inherited confirm.

hx-prompt

Show a browser prompt() dialog. The user's response is sent in the HX-Prompt request header.

<button hx-post="/rename" hx-prompt="Enter new name:">Rename</button>

Inheritance Control

Most hx-* attributes inherit from parent to child elements. Not inherited: hx-trigger, hx-on*, hx-swap-oob, hx-preserve, hx-history-elt, hx-validate.

hx-disinherit

Disable inheritance of specific attributes for child elements.

<!-- Disable all inheritance -->
<div hx-confirm="Sure?" hx-disinherit="*">
    <button hx-delete="/item/1">No confirm dialog</button>
</div>

<!-- Disable specific attribute inheritance -->
<div hx-target="#results" hx-disinherit="hx-target">
    <button hx-get="/data">Uses own default target</button>
</div>

hx-inherit

Explicitly enable inheritance for specific attributes (useful when htmx.config.disableInheritance = true).

<div hx-target="#results" hx-inherit="hx-target">
    <button hx-get="/data">Inherits hx-target</button>
</div>

Unsetting Inherited Values

Use "unset" as the value to clear an inherited attribute:

<div hx-confirm="Sure?">
    <button hx-get="/safe" hx-confirm="unset">No confirm</button>
</div>

Security Attributes

hx-disable

Completely prevents HTMX processing on the element and all its children. Cannot be overridden by injected content.

<div hx-disable>
    <!-- No HTMX processing here, even if attributes are present -->
    <button hx-get="/data">This will NOT make a request</button>
</div>

Miscellaneous Attributes

hx-boost

Convert standard anchors and forms into AJAX requests targeting the <body>.

<!-- Boost all links and forms in this container -->
<div hx-boost="true">
    <a href="/page">AJAX navigation</a>
    <form action="/submit" method="post">
        <button type="submit">AJAX submit</button>
    </form>
</div>

Boosted anchors push the URL into browser history. Boosted forms do NOT push URL — add hx-push-url="true" explicitly if needed. Boosted pages must serve full HTML pages. They degrade gracefully when JS is disabled. Only same-domain links are boosted; local anchor links are ignored.

hx-ext

Enable HTMX extensions on an element and its children.

<!-- Single extension -->
<div hx-ext="preload">...</div>

<!-- Multiple extensions -->
<div hx-ext="preload, response-targets">...</div>

<!-- Disable an inherited extension -->
<div hx-ext="ignore:preload">...</div>

hx-preserve

Keep an element unchanged across swaps. The element must have an id. Useful for video players, iframes, or complex widgets.

<video id="player" hx-preserve>
    <source src="video.mp4" />
</video>

hx-sync

Control how requests from multiple elements are synchronized.

<!-- Abort this request if the form submits -->
<input hx-get="/search" hx-trigger="keyup" hx-sync="closest form:abort" />

<!-- Drop new requests while one is in flight -->
<button hx-post="/action" hx-sync="this:drop">Submit</button>

<!-- Queue requests, keep last -->
<input hx-get="/search" hx-sync="this:queue last" />
StrategyBehavior
dropDrop new request if one is in flight
abortAbort the current request and issue new one
replaceAbort current request, issue new one (alias for abort)
queue firstQueue first request, drop subsequent
queue lastQueue most recent request, drop earlier queued
queue allQueue all requests

hx-validate

Force elements to validate themselves before a request is issued.

<input hx-get="/check" hx-validate="true" required pattern="[a-z]+" />

hx-request

Configure various aspects of the request.

<!-- Set timeout -->
<button hx-get="/slow" hx-request='"timeout": 5000'>Load</button>

<!-- Disable credentials -->
<button hx-get="/api" hx-request='"credentials": false'>Load</button>

<!-- Disable no-cache header -->
<button hx-get="/api" hx-request='"noHeaders": true'>Load</button>

hx-on

Respond to any event directly with inline JavaScript. Uses hx-on:<event-name> or hx-on-<event-name> syntax (colon or dash separator).

<!-- Standard DOM events -->
<button hx-on:click="alert('clicked!')">Click</button>

<!-- HTMX events (use kebab-case for camelCase events) -->
<form hx-post="/submit" hx-on:htmx:before-request="showSpinner()">
    <button type="submit">Submit</button>
</form>

<!-- Modify request parameters -->
<div hx-get="/data" hx-on:htmx:config-request="event.detail.parameters.extra = 'value'">
    Load
</div>

Note: HTML attributes are case-insensitive. Use kebab-case for camelCase event names (e.g., htmx:config-request instead of htmx:configRequest).

references

attributes.md

events-api.md

extensions.md

gotchas.md

patterns.md

REFERENCE.md

requests.md

swapping.md

SKILL.md

tile.json