Htmx Basics
Core HTMX attributes and fundamental patterns for hypermedia-driven web development
You are an expert in HTMX core attributes and fundamental hypermedia-driven development patterns. ## Key Points - `innerHTML` (default) — replaces the inner content of the target - `outerHTML` — replaces the entire target element - `beforebegin` — inserts before the target - `afterbegin` — inserts as the first child of the target - `beforeend` — inserts as the last child of the target - `afterend` — inserts after the target - `delete` — removes the target - `none` — does not insert content - `HX-Request: true` — identifies HTMX requests - `HX-Target` — the id of the target element - `HX-Trigger` — the id of the triggered element - `HX-Current-URL` — the current page URL ## Quick Example ```html <!-- Load content on click --> <button hx-get="/api/users" hx-target="#user-list" hx-swap="innerHTML"> Load Users </button> <div id="user-list"></div> ``` ```html <button hx-get="/slow-endpoint" hx-indicator="#spinner"> Fetch Data </button> <span id="spinner" class="htmx-indicator">Loading...</span> ```
skilldb get htmx-skills/Htmx BasicsFull skill: 168 linesHTMX Basics — HTMX
You are an expert in HTMX core attributes and fundamental hypermedia-driven development patterns.
Overview
HTMX extends HTML with attributes that let any element issue HTTP requests and swap content into the DOM — no JavaScript required. It brings the power of AJAX, CSS transitions, WebSockets, and server-sent events directly into HTML, embracing the original hypermedia model of the web while enabling modern interactive experiences.
Core Concepts
HTMX Request Attributes
HTMX provides attributes that map directly to HTTP methods:
| Attribute | HTTP Method | Purpose |
|---|---|---|
hx-get | GET | Fetch and display content |
hx-post | POST | Submit data to the server |
hx-put | PUT | Update a resource |
hx-patch | PATCH | Partially update a resource |
hx-delete | DELETE | Remove a resource |
The Swap Model
hx-swap controls how the response HTML is inserted into the DOM:
innerHTML(default) — replaces the inner content of the targetouterHTML— replaces the entire target elementbeforebegin— inserts before the targetafterbegin— inserts as the first child of the targetbeforeend— inserts as the last child of the targetafterend— inserts after the targetdelete— removes the targetnone— does not insert content
Targeting
hx-target specifies which element receives the response content. It accepts CSS selectors, plus special values like this, closest <selector>, find <selector>, next <selector>, and previous <selector>.
Triggering
hx-trigger controls when the request fires. Defaults vary by element type (click for buttons, submit for forms, change for inputs). Custom trigger specifications support modifiers like delay, throttle, changed, once, and from.
Implementation Patterns
Basic Content Loading
<!-- Load content on click -->
<button hx-get="/api/users" hx-target="#user-list" hx-swap="innerHTML">
Load Users
</button>
<div id="user-list"></div>
Click-to-Edit Pattern
<!-- Display mode -->
<div hx-get="/contacts/1/edit" hx-trigger="click" hx-swap="outerHTML">
<p>John Doe</p>
<p>john@example.com</p>
</div>
<!-- Server returns edit form -->
<form hx-put="/contacts/1" hx-swap="outerHTML">
<input name="name" value="John Doe">
<input name="email" value="john@example.com">
<button type="submit">Save</button>
<button hx-get="/contacts/1" hx-swap="outerHTML">Cancel</button>
</form>
Delete with Confirmation
<button hx-delete="/items/42"
hx-confirm="Are you sure?"
hx-target="closest tr"
hx-swap="outerHTML swap:500ms">
Delete
</button>
Loading Indicators
<button hx-get="/slow-endpoint" hx-indicator="#spinner">
Fetch Data
</button>
<span id="spinner" class="htmx-indicator">Loading...</span>
HTMX automatically adds the htmx-request class to the element (or indicator) during the request. Use CSS to show/hide:
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
display: inline;
}
Including Extra Values
<div hx-get="/search" hx-include="[name='query'], [name='page']">
<input name="query" value="htmx">
<input name="page" value="1" type="hidden">
<button>Search</button>
</div>
Request Headers
HTMX sends useful headers with every request:
HX-Request: true— identifies HTMX requestsHX-Target— the id of the target elementHX-Trigger— the id of the triggered elementHX-Current-URL— the current page URL
Servers can check HX-Request to return partial HTML instead of full pages.
Core Philosophy
HTMX is built on the conviction that hypermedia, not JSON APIs and client-side rendering, is the natural architecture of the web. HTML was always meant to be the engine of application state. HTMX extends this by letting any element issue HTTP requests and receive HTML responses, bringing AJAX capability to the markup layer without requiring a JavaScript framework or build step.
The library deliberately constrains you to the server-rendered HTML model. There is no client-side component tree, no virtual DOM diffing, and no state management layer. The server is the single source of truth, and the client is a thin rendering surface. This constraint eliminates entire categories of bugs (state synchronization, cache invalidation, client/server drift) and dramatically reduces the JavaScript shipped to users.
HTMX attributes are designed to be self-documenting. Reading hx-get="/contacts", hx-target="#list", hx-swap="innerHTML" tells you exactly what happens, where the response goes, and how it is inserted. This transparency means anyone who understands HTML can understand the interactive behavior of the page, lowering the barrier to contribution and debugging. The absence of hidden wiring is a feature, not a limitation.
Anti-Patterns
-
Returning full HTML pages instead of targeted fragments. If the server does not distinguish HTMX requests from normal navigation, users see nested pages rendered inside a small target area. Always check the
HX-Requestheader and return just the fragment. -
Over-targeting large DOM sections. Swapping the entire
<body>or a massive<main>on every interaction defeats the purpose of partial updates. Keep swap targets small and responses focused on the content that actually changed. -
Building client-side state alongside HTMX. Maintaining a JavaScript state object that duplicates what the server already knows creates synchronization bugs. Let the server own all state and use HTMX to reflect it in the DOM.
-
Omitting
hx-swap="none"for fire-and-forget requests. If a request does not need to update the DOM (analytics pings, background saves), leavinghx-swapat its defaultinnerHTMLcauses unexpected content replacement. Explicitly set it tonone. -
Forgetting CSRF tokens on mutating requests. HTMX POST, PUT, PATCH, and DELETE requests need the same CSRF protection as regular forms. Configure
hx-headersat the body level or use a global event listener to attach the token to every request.
Best Practices
- Return HTML, not JSON. HTMX works with hypermedia responses. The server should return rendered HTML fragments.
- Use
hx-targetexplicitly. While HTMX defaults to the issuing element, explicitly setting targets makes behavior self-documenting. - Leverage
hx-swapmodifiers. Add timing withswap:300msorsettle:200msfor smooth transitions. Useshow:topto scroll into view. - Boost existing links and forms. Use
hx-boost="true"on a parent element to progressively enhance standard navigation with AJAX without changing your markup. - Set defaults at the body level. Use
hx-headers,hx-target, orhx-swapon<body>to establish application-wide defaults and reduce repetition. - Use
hx-push-urlto update the browser URL bar when replacing significant content, preserving deep-link and back-button behavior.
Common Pitfalls
- Returning full pages instead of fragments. If the server does not distinguish HTMX requests from normal navigation, users see nested pages. Always check the
HX-Requestheader. - Forgetting CSRF tokens. HTMX POST/PUT/DELETE requests need CSRF protection. Use
hx-headersor configure a globalhtmx.config.getCacheBusterParam/ event listener to include tokens. - Over-targeting. Swapping large DOM sections defeats the purpose. Keep targets small and responses focused.
- Ignoring the
htmx:afterSwapevent. Third-party JavaScript (charts, date pickers) that initializes on page load will not re-initialize after a swap unless you listen for HTMX lifecycle events. - Not setting
hx-swap="none"for fire-and-forget requests. If you do not need to update the DOM, explicitly sethx-swap="none"to avoid unexpected content replacement.
Install this skill directly: skilldb add htmx-skills
Related Skills
Htmx Active Search
Active search, typeahead, and autocomplete patterns using HTMX triggers and debouncing
Htmx Alpine Integration
Combining Alpine.js with HTMX for client-side state and interactivity alongside hypermedia-driven updates
Htmx Backend Patterns
Server-side patterns for HTMX including partial templates, response headers, and middleware
Htmx Forms
Form handling, validation, and submission patterns with HTMX
Htmx Infinite Scroll
Infinite scroll and lazy loading patterns using HTMX revealed and intersect triggers
Htmx Progressive Enhancement
Progressive enhancement strategies for building HTMX applications that work without JavaScript