Skip to main content
Technology & EngineeringHtmx168 lines

Htmx Basics

Core HTMX attributes and fundamental patterns for hypermedia-driven web development

Quick Summary35 lines
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 lines
Paste into your CLAUDE.md or agent config

HTMX 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:

AttributeHTTP MethodPurpose
hx-getGETFetch and display content
hx-postPOSTSubmit data to the server
hx-putPUTUpdate a resource
hx-patchPATCHPartially update a resource
hx-deleteDELETERemove 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 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

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 requests
  • HX-Target — the id of the target element
  • HX-Trigger — the id of the triggered element
  • HX-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-Request header 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), leaving hx-swap at its default innerHTML causes unexpected content replacement. Explicitly set it to none.

  • Forgetting CSRF tokens on mutating requests. HTMX POST, PUT, PATCH, and DELETE requests need the same CSRF protection as regular forms. Configure hx-headers at 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-target explicitly. While HTMX defaults to the issuing element, explicitly setting targets makes behavior self-documenting.
  • Leverage hx-swap modifiers. Add timing with swap:300ms or settle:200ms for smooth transitions. Use show:top to 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, or hx-swap on <body> to establish application-wide defaults and reduce repetition.
  • Use hx-push-url to 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-Request header.
  • Forgetting CSRF tokens. HTMX POST/PUT/DELETE requests need CSRF protection. Use hx-headers or configure a global htmx.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:afterSwap event. 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 set hx-swap="none" to avoid unexpected content replacement.

Install this skill directly: skilldb add htmx-skills

Get CLI access →