Write, Run & Share HTMX code online using OneCompiler's HTMX online editor for free. It's one of the robust, feature-rich online editors for HTMX. Getting started with the OneCompiler's HTMX online editor is really simple and pretty fast. The editor shows sample boilerplate code when you choose language as 'HTMX' and start writing code to learn and test online without worrying about tedious process of installation.
HTMX is a lightweight JavaScript library that allows you to access modern browser features directly from HTML, without writing JavaScript. It extends HTML with attributes that enable AJAX requests, CSS transitions, WebSockets, and Server-Sent Events. HTMX promotes the hypermedia approach where the server returns HTML instead of JSON, simplifying web development.
HTMX uses special attributes prefixed with hx- to define behavior directly in your HTML elements. The hx-get, hx-post, hx-put, hx-patch, and hx-delete attributes specify which HTTP method to use and the URL to request. When triggered, HTMX makes an AJAX request and swaps the returned HTML into the page. This approach keeps your markup declarative and eliminates the need for JavaScript event handlers.
<!-- HTTP methods: hx-get, hx-post, hx-put, hx-patch, hx-delete -->
<button hx-get="/api/data">Load Data</button>
<button hx-post="/api/submit">Submit</button>
<button hx-delete="/api/item/1">Delete</button>
<!-- With URL parameters -->
<button hx-get="/search?q=htmx">Search</button>
The hx-target attribute specifies where the response HTML should be inserted in the page, using CSS selectors. By default, HTMX replaces the content of the element that triggered the request, but you can target any element on the page. Special values like this, closest, find, and next help you target elements relative to the trigger. This separation of trigger and target enables powerful UI patterns like updating a list after adding an item.
<!-- Target by ID -->
<button hx-get="/api/users" hx-target="#user-list">Load Users</button>
<div id="user-list"></div>
<!-- Target by CSS selector -->
<button hx-get="/api/data" hx-target=".results">Load</button>
<!-- Relative targets: this, closest, find, next, previous -->
<div class="container">
<button hx-get="/api/data" hx-target="closest div">Update Parent</button>
</div>
<!-- Target with find (searches descendants) -->
<div>
<button hx-get="/api/data" hx-target="find .content">Load</button>
<div class="content"></div>
</div>
The hx-swap attribute controls how the returned HTML is inserted into the target element. The default innerHTML replaces the target's content, while outerHTML replaces the entire target element. Other options like beforebegin, afterend, beforeend, and afterbegin let you insert content around or inside the target without removing existing content. You can also add modifiers for transitions, scrolling, and timing.
<!-- Swap modes: innerHTML (default), outerHTML, beforebegin, afterbegin, beforeend, afterend, delete, none -->
<button hx-get="/api/item" hx-swap="innerHTML">Replace Content</button>
<button hx-get="/api/item" hx-swap="outerHTML">Replace Element</button>
<button hx-get="/api/item" hx-swap="beforeend">Append</button>
<button hx-get="/api/item" hx-swap="afterbegin">Prepend</button>
<!-- Swap modifiers: transition, swap, settle, scroll, show -->
<button hx-get="/api/data" hx-swap="innerHTML transition:true">
With Transition
</button>
<button hx-get="/api/data" hx-swap="innerHTML swap:1s">Delay Swap 1s</button>
<button hx-get="/api/data" hx-swap="innerHTML scroll:top">Scroll to Top</button>
The hx-trigger attribute defines which events cause the HTMX request to fire. By default, buttons use click and inputs use change, but you can specify any DOM event like mouseenter, keyup, or custom events. Trigger modifiers add conditions like once (fire only once), changed (only if value changed), delay (debounce), and throttle. You can also combine multiple triggers separated by commas.
<!-- Event triggers: click (default for buttons), change, submit, keyup, mouseenter, load, revealed, intersect -->
<input hx-get="/api/search" hx-trigger="keyup" />
<div hx-get="/api/data" hx-trigger="mouseenter">Hover to Load</div>
<div hx-get="/api/data" hx-trigger="load">Load on Page Load</div>
<div hx-get="/api/data" hx-trigger="revealed">Load When Visible</div>
<!-- Trigger modifiers: once, changed, delay, throttle, from -->
<input
hx-get="/api/search"
hx-trigger="keyup changed delay:500ms"
hx-target="#results"
/>
<button hx-get="/api/data" hx-trigger="click once">Load Once</button>
<input hx-get="/api/search" hx-trigger="keyup throttle:1s" />
<!-- Multiple triggers -->
<input hx-get="/api/validate" hx-trigger="change, keyup delay:500ms" />
HTMX makes form handling seamless by automatically including form data in requests without page reloads. When you add hx-post to a form, it submits via AJAX and swaps the response into the page. The hx-include attribute lets you include values from elements outside the form, while hx-vals adds extra static values to the request. Form validation still works normally, and you can handle validation errors by returning appropriate HTML from the server.
<!-- Basic form submission -->
<form hx-post="/api/submit" hx-target="#result">
<input type="text" name="username" placeholder="Username" />
<input type="email" name="email" placeholder="Email" />
<button type="submit">Submit</button>
</form>
<div id="result"></div>
<!-- Include additional elements -->
<input type="text" id="extra" name="extra" value="additional data" />
<form hx-post="/api/submit" hx-include="#extra">
<input type="text" name="name" />
<button type="submit">Submit</button>
</form>
<!-- Add static values with hx-vals -->
<button hx-post="/api/action" hx-vals='{"type": "premium", "source": "button"}'>
Premium Action
</button>
<!-- JSON encoding: hx-vals='js:{...}' for dynamic values -->
<button hx-post="/api/action" hx-vals="js:{timestamp: Date.now()}">
Submit
</button>
Loading indicators provide visual feedback during AJAX requests, improving user experience for slower operations. The hx-indicator attribute specifies an element (using CSS selector) to show while the request is in progress. HTMX automatically adds the htmx-request class to the indicator during requests, which you can style with CSS to show spinners, progress bars, or loading text. The .htmx-indicator class provides a convenient default that hides by default and shows during requests.
<!-- Basic indicator -->
<button hx-get="/api/slow" hx-indicator="#spinner">
Load Data
<span id="spinner" class="htmx-indicator">Loading...</span>
</button>
<!-- CSS for htmx-indicator class (hides by default, shows during request) -->
<style>
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator {
display: inline;
}
.htmx-request.htmx-indicator {
display: inline;
}
</style>
<!-- Indicator on different element -->
<div>
<button hx-get="/api/data" hx-indicator="#global-spinner">Load</button>
</div>
<div id="global-spinner" class="htmx-indicator">
<img src="/spinner.gif" alt="Loading" />
</div>
HTMX sends useful headers with each request that help the server determine how to respond. The HX-Request header indicates the request came from HTMX, HX-Target contains the target element's ID, and HX-Trigger identifies which element triggered the request. You can add custom headers with hx-headers for authentication tokens or other metadata. These headers enable servers to return full pages for direct navigation and partial HTML for HTMX requests.
<!-- Add custom headers -->
<button hx-get="/api/data" hx-headers='{"X-Custom-Header": "value"}'>
Load with Header
</button>
<!-- Authentication header -->
<div hx-headers='{"Authorization": "Bearer token123"}'>
<button hx-get="/api/protected">Load Protected</button>
<button hx-post="/api/action">Protected Action</button>
</div>
<!-- HTMX automatically sends these headers:
HX-Request: true
HX-Target: (id of target element)
HX-Trigger: (id of trigger element)
HX-Trigger-Name: (name of trigger element)
HX-Current-URL: (current page URL)
-->
The hx-boost attribute progressively enhances standard links and forms to use AJAX, maintaining normal functionality for users without JavaScript. Boosted links load content via AJAX while updating the browser URL and history, enabling back/forward navigation. The hx-push-url and hx-replace-url attributes give you explicit control over history behavior. This approach lets you build fast, app-like experiences while keeping your site accessible and SEO-friendly.
<!-- Boost all links and forms in a container -->
<div hx-boost="true">
<a href="/page1">Page 1</a>
<a href="/page2">Page 2</a>
<form action="/submit" method="post">
<input name="data" />
<button>Submit</button>
</form>
</div>
<!-- Control URL/history behavior -->
<a hx-get="/page" hx-push-url="true">Push to History</a>
<a hx-get="/page" hx-push-url="/custom-url">Push Custom URL</a>
<a hx-get="/modal" hx-push-url="false">Don't Change URL</a>
<a hx-get="/page" hx-replace-url="true">Replace Current URL</a>
HTMX supports automatic polling to keep content fresh and Server-Sent Events (SSE) for real-time updates from the server. The every trigger modifier sets up polling at specified intervals, perfect for dashboards or live data feeds. For true real-time updates, SSE lets the server push HTML updates to the client as events occur. Both approaches keep the hypermedia philosophy by transferring HTML rather than raw data.
<!-- Polling: refresh content at intervals -->
<div hx-get="/api/notifications" hx-trigger="every 5s">
<!-- Content refreshed every 5 seconds -->
</div>
<!-- Polling with load (immediate first load) -->
<div hx-get="/api/status" hx-trigger="load, every 10s">Loading status...</div>
<!-- Server-Sent Events (SSE) -->
<div hx-ext="sse" sse-connect="/events">
<div sse-swap="message">Waiting for messages...</div>
<div sse-swap="notification">Waiting for notifications...</div>
</div>
<!-- WebSocket support -->
<div hx-ext="ws" ws-connect="/chat">
<div id="messages"></div>
<form ws-send>
<input name="message" />
<button>Send</button>
</form>
</div>
HTMX provides built-in confirmation dialogs and validation hooks to prevent accidental actions or invalid submissions. The hx-confirm attribute shows a browser confirmation dialog before proceeding with the request. For custom validation, you can use the htmx:configRequest event to cancel requests or modify them based on validation logic. The hx-validate attribute triggers HTML5 form validation before submitting.
<!-- Confirmation dialog -->
<button
hx-delete="/api/item/1"
hx-confirm="Are you sure you want to delete this?"
>
Delete Item
</button>
<!-- Form validation (triggers HTML5 validation) -->
<form hx-post="/api/submit" hx-validate="true">
<input type="email" name="email" required />
<button type="submit">Submit</button>
</form>
<!-- Disable element during request -->
<button hx-post="/api/action" hx-disabled-elt="this">
Click Me (disables during request)
</button>
<!-- Disable multiple elements -->
<button hx-post="/api/action" hx-disabled-elt="#btn1, #btn2, .submit-btns">
Submit
</button>
Out-of-band (OOB) swaps allow a single response to update multiple parts of the page simultaneously. The server includes additional elements with hx-swap-oob="true" in the response, and HTMX swaps each one into its matching element by ID. This is powerful for updating related UI components like notification counts, status indicators, or lists from a single request. OOB swaps reduce the need for multiple requests and keep related updates synchronized.
<!-- Server response with OOB swaps -->
<!--
Response HTML:
<div id="main-content">Updated main content</div>
<div id="notification-count" hx-swap-oob="true">5</div>
<div id="last-updated" hx-swap-oob="true">Just now</div>
-->
<!-- The trigger element -->
<button hx-get="/api/data" hx-target="#main-content">Load Data</button>
<div id="main-content"></div>
<!-- These get updated via OOB -->
<span id="notification-count">0</span>
<span id="last-updated">Never</span>
<!-- OOB with swap strategy -->
<!-- hx-swap-oob="true" | "innerHTML" | "outerHTML" | "beforeend" etc. -->
HTMX fires custom events throughout the request lifecycle that you can hook into for custom behavior. Events like htmx:beforeRequest, htmx:afterSwap, and htmx:responseError let you add logging, animations, or error handling. Extensions add additional functionality like JSON encoding, client-side templates, or morphing animations. The extension system is modular, so you only include what you need.
<!-- Listen to HTMX events -->
<script>
// Before request is sent
document.body.addEventListener("htmx:beforeRequest", function (evt) {
console.log("Request starting", evt.detail)
})
// After content is swapped
document.body.addEventListener("htmx:afterSwap", function (evt) {
console.log("Content swapped", evt.detail.target)
})
// Handle errors
document.body.addEventListener("htmx:responseError", function (evt) {
console.error("Request failed", evt.detail.xhr.status)
})
</script>
<!-- Common extensions: json-enc, client-side-templates, morphdom-swap, class-tools -->
<script src="https://unpkg.com/htmx.org/dist/ext/json-enc.js"></script>
<form hx-ext="json-enc" hx-post="/api/data">
<!-- Form data sent as JSON -->
</form>
<!-- Class tools extension for adding/removing classes -->
<div
hx-get="/api/data"
hx-ext="class-tools"
classes="add fade-in:1s, remove loading:2s"
>
Content
</div>