Loading...
Loading...
Provides guidance for building dynamic interactive web applications using htmx library with AJAX requests and dynamic content swapping
npx skill4agent add the-perfect-developer/the-perfect-opencode htmxhx-get="/url"hx-post="/url"hx-put="/url"hx-patch="/url"hx-delete="/url"<button hx-post="/clicked" hx-target="#result">
Click Me!
</button>
<div id="result"></div>hx-triggerinput/textarea/selectchangeformsubmitclick<!-- Trigger on mouseenter -->
<div hx-get="/data" hx-trigger="mouseenter">Hover me</div>
<!-- Trigger on keyup with delay -->
<input hx-get="/search" hx-trigger="keyup changed delay:500ms">
<!-- Multiple triggers -->
<div hx-get="/data" hx-trigger="mouseenter, focus">oncechangeddelay:500msthrottle:1sfrom:<selector><!-- Only trigger if Ctrl key pressed -->
<div hx-get="/clicked" hx-trigger="click[ctrlKey]">Ctrl+Click</div>loadrevealedevery 2shx-target<button hx-get="/data" hx-target="#result">Load</button>
<div id="result"></div>thisclosest <selector>next <selector>previous <selector>find <selector>hx-swapinnerHTMLouterHTMLafterbeginbeforebeginbeforeendafterenddeletenone<button hx-get="/data" hx-swap="innerHTML swap:100ms settle:200ms"><button hx-get="/slow">
Click Me!
<img class="htmx-indicator" src="/spinner.gif">
</button>htmx-indicatoropacity:0htmx-request<button hx-get="/data" hx-indicator="#loading">Load</button>
<div id="loading" class="htmx-indicator">Loading...</div><input type="text" name="q"
hx-get="/search"
hx-trigger="keyup changed delay:500ms"
hx-target="#search-results"
placeholder="Search...">
<div id="search-results"></div><div hx-get="/more-items"
hx-trigger="revealed"
hx-swap="afterend">
Load More...
</div><div hx-get="/edit/123" hx-target="this" hx-swap="outerHTML">
<label>Name:</label> John Doe
</div><button hx-delete="/item/123"
hx-confirm="Are you sure?"
hx-target="closest tr"
hx-swap="outerHTML swap:1s">
Delete
</button><!-- Response HTML -->
<div id="main-content">Main update</div>
<div id="notification" hx-swap-oob="true">
New notification!
</div>hx-swap-oob="true"<form hx-post="/submit" hx-target="#result">
<input name="email" type="email">
<button type="submit">Submit</button>
</form><!-- Include other elements -->
<button hx-post="/save"
hx-include="[name='email']">
Save
</button>
<!-- Add extra values -->
<button hx-post="/save"
hx-vals='{"priority": "high"}'>
Save
</button><form hx-post="/upload"
hx-encoding="multipart/form-data"
hx-target="#result">
<input type="file" name="file">
<button type="submit">Upload</button>
</form>htmx.on('htmx:xhr:progress', function(evt) {
htmx.find('#progress').value = evt.detail.loaded/evt.detail.total * 100;
});hx-sync<form hx-post="/store">
<input name="title"
hx-post="/validate"
hx-trigger="change"
hx-sync="closest form:abort">
<button type="submit">Submit</button>
</form>dropabortreplacequeue<div hx-boost="true">
<a href="/page1">Page 1</a>
<a href="/page2">Page 2</a>
</div><a hx-get="/blog" hx-push-url="true">Blog</a><div hx-history="false">Sensitive content</div>HX-Request: trueHX-TriggerHX-TargetHX-Current-URLHX-Promptif request.headers.get('HX-Request'):
return render_template('partial.html')
return render_template('full_page.html')HX-TriggerHX-RedirectHX-LocationHX-RefreshHX-RetargetHX-Reswapresponse.headers['HX-Trigger'] = 'itemUpdated'
response.headers['HX-Trigger'] = '{"showMessage": "Saved!"}'<form hx-post="/submit">
<input name="email" type="email" required>
<button type="submit">Submit</button>
</form>htmx.config.reportValidityOfForms = truehtmx.on('htmx:validation:validate', function(evt) {
if (evt.target.value === 'forbidden') {
evt.target.setCustomValidity('This value is forbidden');
evt.detail.valid = false;
}
});hx-on<button hx-get="/data"
hx-on::before-request="this.classList.add('loading')"
hx-on::after-request="this.classList.remove('loading')">
Load
</button>// Trigger requests programmatically
htmx.ajax('GET', '/data', '#target');
// Listen to events
htmx.on('htmx:afterSwap', function(evt) {
console.log('Content swapped');
});
// Process new content
htmx.process(document.body);
// Trigger events
htmx.trigger('#element', 'myEvent', {detail: {foo: 'bar'}});<!-- Before -->
<div id="content">Old content</div>
<!-- After (same ID) -->
<div id="content" class="highlight">New content</div>.highlight {
background-color: yellow;
transition: background-color 1s ease-in;
}<meta name="htmx-config" content='{
"defaultSwapStyle": "outerHTML",
"defaultSwapDelay": 100,
"defaultSettleDelay": 200,
"historyCacheSize": 20
}'>htmx.config.defaultSwapStyle = 'outerHTML';
htmx.config.timeout = 5000; // 5 second timeout<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"></script>npm install htmx.org@2.0.8import 'htmx.org';<script src="/js/htmx.min.js"></script>hx-boosthtmx:responseErrorhtmx:sendErrorhtmx.config.reportValidityOfForms = truehtmx.logAll();htmx.logger = function(elt, event, data) {
if(console) {
console.log(event, elt, data);
}
}HX-*htmx-*references/attributes.mdreferences/events.mdreferences/examples.mdreferences/server-side.md