<!-- CDN -->
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<!-- NPM -->
npm install htmx.org
<!-- ESM -->
import htmx from 'htmx.org'; <!-- GET request -->
<button hx-get="/api/data">Load Data</button>
<!-- POST request -->
<form hx-post="/api/submit">
<input name="email" type="email">
<button type="submit">Submit</button>
</form>
<!-- PUT request -->
<button hx-put="/api/item/1">Update</button>
<!-- PATCH request -->
<button hx-patch="/api/item/1">Patch</button>
<!-- DELETE request -->
<button hx-delete="/api/item/1">Delete</button> <!-- Target by ID -->
<button hx-get="/data" hx-target="#result">Load</button>
<div id="result"></div>
<!-- Target selectors -->
hx-target="this" <!-- Current element -->
hx-target="closest div" <!-- Closest ancestor -->
hx-target="next .item" <!-- Next sibling -->
hx-target="previous .item" <!-- Previous sibling -->
hx-target="find .child" <!-- Child element --> <!-- Swap strategies -->
hx-swap="innerHTML" <!-- Replace inner HTML (default) -->
hx-swap="outerHTML" <!-- Replace entire element -->
hx-swap="beforebegin" <!-- Insert before element -->
hx-swap="afterbegin" <!-- Insert at start of element -->
hx-swap="beforeend" <!-- Insert at end of element -->
hx-swap="afterend" <!-- Insert after element -->
hx-swap="delete" <!-- Delete element -->
hx-swap="none" <!-- No swap -->
<!-- With modifiers -->
hx-swap="innerHTML swap:1s" <!-- Wait 1s before swap -->
hx-swap="innerHTML settle:500ms" <!-- Settle delay -->
hx-swap="innerHTML scroll:top" <!-- Scroll to top after swap --> <!-- Default: click for buttons, submit for forms -->
<button hx-get="/api">Click me</button>
<!-- Custom events -->
hx-trigger="click" <!-- On click -->
hx-trigger="mouseenter" <!-- On hover -->
hx-trigger="keyup" <!-- On keyup -->
hx-trigger="load" <!-- On element load -->
hx-trigger="revealed" <!-- When scrolled into view -->
hx-trigger="intersect" <!-- Intersection observer -->
<!-- Modifiers -->
hx-trigger="click once" <!-- Only once -->
hx-trigger="keyup changed delay:500ms" <!-- Debounce -->
hx-trigger="keyup throttle:500ms" <!-- Throttle -->
hx-trigger="click from:body" <!-- Event from body -->
hx-trigger="every 2s" <!-- Polling --> <!-- Search as you type -->
<input type="search"
name="q"
hx-get="/search"
hx-trigger="keyup changed delay:300ms"
hx-target="#results">
<div id="results"></div>
<!-- Infinite scroll -->
<div hx-get="/items?page=2"
hx-trigger="revealed"
hx-swap="afterend">
Loading more...
</div> <!-- Basic form -->
<form hx-post="/api/users" hx-target="#message">
<input name="name" required>
<input name="email" type="email" required>
<button type="submit">Create User</button>
</form>
<div id="message"></div>
<!-- Include extra values -->
<form hx-post="/submit" hx-vals='{"extra": "data"}'>
...
</form>
<!-- Include values from other elements -->
<form hx-post="/submit" hx-include="[name='csrf']">
...
</form>
<input type="hidden" name="csrf" value="token123"> <!-- Loading indicator -->
<button hx-get="/slow-request" hx-indicator="#spinner">
Load Data
</button>
<span id="spinner" class="htmx-indicator">Loading...</span>
<style>
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator {
display: inline;
}
.htmx-request.htmx-indicator {
display: inline;
}
</style>
<!-- Disable button during request -->
<button hx-get="/api" hx-disabled-elt="this">
Click me
</button> <!-- Add custom headers -->
<button hx-get="/api"
hx-headers='{"X-Custom-Header": "value"}'>
Load
</button>
<!-- Confirm before request -->
<button hx-delete="/item/1"
hx-confirm="Are you sure?">
Delete
</button>
<!-- Validation -->
<form hx-post="/submit"
hx-validate="true">
<input name="email" type="email" required>
<button type="submit">Submit</button>
</form> <!-- Server can control htmx via headers -->
HX-Redirect: /new-page <!-- Redirect -->
HX-Refresh: true <!-- Refresh page -->
HX-Retarget: #other <!-- Change target -->
HX-Reswap: outerHTML <!-- Change swap -->
HX-Trigger: myEvent <!-- Trigger event -->
HX-Push-Url: /new-url <!-- Push to history --> // Listen to htmx events
document.body.addEventListener("htmx:beforeRequest", (e) => {
console.log("Request starting", e.detail);
});
document.body.addEventListener("htmx:afterSwap", (e) => {
console.log("Content swapped", e.detail);
});
document.body.addEventListener("htmx:responseError", (e) => {
console.log("Error", e.detail.xhr.status);
});
// Key events:
// htmx:configRequest - Before request is configured
// htmx:beforeRequest - Before request is sent
// htmx:afterRequest - After request completes
// htmx:beforeSwap - Before content is swapped
// htmx:afterSwap - After content is swapped
// htmx:afterSettle - After settling is complete