1<!doctype html> 2<html lang="en"> 3<head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1"> 6 <meta name="description" content="htmx gives you access to AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML, using attributes, so you can build modern user interfaces with the simplicity and power of hypertext 7 8 htmx is small (~14k min.gzâd), dependency-free, extendable, IE11 compatible & has reduced code base sizes by 67% when compared with react"> 9 10 <title></> htmx ~ Documentation</title> 11 <link rel="canonical" href="https://htmx.org/docs/"> 12 13 <link rel="alternate" type="application/atom+xml" title="Sitewide Atom feed" href="/atom.xml"> 14 <link rel="stylesheet" href="/css/site.css"> 15 <link rel="icon" href="/favicon.svg" type="image/svg+xml"> 16
16<script src="/js/htmx.js"></script>
16 17
17<script src="/js/class-tools.js"></script>
17 18
18<script src="/js/preload.js"></script>
18 19 20
20<script src="/js/_hyperscript.js"></script>
20 21 <meta name="generator" content="Zola v.TODO"> 22</head> 23<body hx-ext="class-tools, preload"> 24 25<header class="top-nav"> 26 <div class="c"> 27 <div class="menu"> 28 <div class="logo-wrapper"> 29 <a href="/" class="logo light"><<b>/</b>> htm<b>x</b></a> 30 <svg _="on click toggle .show on #nav" class="hamburger" viewBox="0 0 100 80" width="25" height="25" style="margin-bottom:-5px"> 31 <rect width="100" height="20" style="fill:rgb(52, 101, 164)" rx="10"></rect> 32 <rect y="30" width="100" height="20" style="fill:rgb(52, 101, 164)" rx="10"></rect> 33 <rect y="60" width="100" height="20" style="fill:rgb(52, 101, 164)" rx="10"></rect> 34 </svg> 35 </div> 36 37 <div id="nav" class="navigation" hx-boost="true"> 38 39 <nav class="navigation-items" preload="mouseover"> 40 <div><a href="/docs/">docs</a></div> 41 <div><a href="/reference/">reference</a></div> 42 <div><a href="/examples/">examples</a></div> 43 <div><a href="/talk/">talk</a></div> 44 <div><a href="/essays/">essays</a></div> 45 <div hx-disable> 46 <form action="https://google.com/search" role="search" aria-label="Sitewide"> 47 <input type="hidden" name="q" value="+[inurl:https://htmx.org]"> 48 <label> 49 <span style="display:none;">Search</span> 50 <input type="text" name="q" placeholder="ðï¸" class="search-box"> 51 </label> 52 </form> 53 </div> 54 <div> 55 <div class="github-stars" hx-preserve="true" id="github-stars"> 56 <a class="github-button" href="https://github.com/bigskysoftware/htmx" data-color-scheme="no-preference: light; light: light; dark: dark;" data-icon="octicon-star" data-show-count="true" aria-label="Star bigskysoftware/htmx on GitHub">star</a> 57 </div> 58 </div> 59 </nav> 60 </div> 61 </div> 62 </div> 63</header> 64 65 66 67 68 69<main class="c content wide-content"> 70 71 <h1>Documentation</h1> 72 <div class="row"> 73<div class="2 col nav"> 74<p><strong>Contents</strong></p> 75<div id="contents"> 76<ul> 77<li><a href="https://htmx.org/docs/#introduction">introduction</a></li> 78<li><a href="https://htmx.org/docs/#installing">installing</a></li> 79<li><a href="https://htmx.org/docs/#ajax">ajax</a> 80<ul> 81<li><a href="https://htmx.org/docs/#triggers">triggers</a> 82<ul> 83<li><a href="https://htmx.org/docs/#trigger-modifiers">trigger modifiers</a></li> 84<li><a href="https://htmx.org/docs/#trigger-filters">trigger filters</a></li> 85<li><a href="https://htmx.org/docs/#special-events">special events</a></li> 86<li><a href="https://htmx.org/docs/#polling">polling</a></li> 87<li><a href="https://htmx.org/docs/#load_polling">load polling</a></li> 88</ul> 89</li> 90<li><a href="https://htmx.org/docs/#indicators">indicators</a></li> 91<li><a href="https://htmx.org/docs/#targets">targets</a></li> 92<li><a href="https://htmx.org/docs/#swapping">swapping</a></li> 93<li><a href="https://htmx.org/docs/#synchronization">synchronization</a></li> 94<li><a href="https://htmx.org/docs/#css_transitions">css transitions</a></li> 95<li><a href="https://htmx.org/docs/#oob_swaps">out of band swaps</a></li> 96<li><a href="https://htmx.org/docs/#partial_swaps">server-sent swap commands</a></li> 97<li><a href="https://htmx.org/docs/#parameters">parameters</a></li> 98<li><a href="https://htmx.org/docs/#confirming">confirming</a></li> 99</ul> 100</li> 101<li><a href="https://htmx.org/docs/#inheritance">inheritance</a></li> 102<li><a href="https://htmx.org/docs/#boosting">boosting</a></li> 103<li><a href="https://htmx.org/docs/#websockets-and-sse">websockets & SSE</a></li> 104<li><a href="https://htmx.org/docs/#history">history</a></li> 105<li><a href="https://htmx.org/docs/#requests">requests & responses</a></li> 106<li><a href="https://htmx.org/docs/#validation">validation</a></li> 107<li><a href="https://htmx.org/docs/#animations">animations</a></li> 108<li><a href="https://htmx.org/docs/#extensions">extensions</a></li> 109<li><a href="https://htmx.org/docs/#events">events & logging</a></li> 110<li><a href="https://htmx.org/docs/#debugging">debugging</a></li> 111<li><a href="https://htmx.org/docs/#scripting">scripting</a> 112<ul> 113<li><a href="https://htmx.org/docs/#hx-on">hx-on attribute</a></li> 114</ul> 115</li> 116<li><a href="https://htmx.org/docs/#3rd-party">3rd party integration</a> 117<ul> 118<li><a href="https://htmx.org/docs/#web-components">Web Components</a></li> 119</ul> 120</li> 121<li><a href="https://htmx.org/docs/#caching">caching</a></li> 122<li><a href="https://htmx.org/docs/#security">security</a></li> 123<li><a href="https://htmx.org/docs/#config">configuring</a></li> 124</ul> 125</div> 126</div> 127<div class="10 col"> 128<h2 id="introduction"><a class="zola-anchor" href="#introduction" aria-label="Anchor link for: introduction">htmx in a Nutshell</a></h2> 129<p>htmx is a library that allows you to access modern browser features directly from HTML, rather than using 130javascript.</p> 131<p>To understand htmx, first letâs take a look at an anchor tag:</p> 132<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/blog"</span><span>>Blog</</span><span style="color:#e06c75;">a</span><span>> 133</span></code></pre> 134<p>This anchor tag tells a browser:</p> 135<blockquote> 136<p>âWhen a user clicks on this link, issue an HTTP GET request to â/blogâ and load the response content 137into the browser windowâ.</p> 138</blockquote> 139<p>With that in mind, consider the following bit of HTML:</p> 140<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/clicked" 141</span><span> </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"click" 142</span><span> </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#parent-div" 143</span><span> </span><span style="color:#d19a66;">hx-swap</span><span>=</span><span style="color:#98c379;">"outerHTML"</span><span>> 144</span><span> Click Me! 145</span><span></</span><span style="color:#e06c75;">button</span><span>> 146</span></code></pre> 147<p>This tells htmx:</p> 148<blockquote> 149<p>âWhen a user clicks on this button, issue an HTTP POST request to â/clickedâ and use the content from the response 150to replace the element with the id <code>parent-div</code> in the DOMâ</p> 151</blockquote> 152<p>htmx extends and generalizes the core idea of HTML as a hypertext, opening up many more possibilities directly 153within the language:</p> 154<ul> 155<li>Now any element, not just anchors and forms, can issue an HTTP request</li> 156<li>Now any event, not just clicks or form submissions, can trigger requests</li> 157<li>Now any <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/HTTP_Verbs">HTTP verb</a>, not just <code>GET</code> and <code>POST</code>, can be used</li> 158<li>Now any element, not just the entire window, can be the target for update by the request</li> 159</ul> 160<p>Note that when you are using htmx, on the server side you typically respond with <em>HTML</em>, not <em>JSON</em>. This keeps you firmly 161within the <a rel="noopener" target="_blank" href="https://roy.gbiv.com/pubs/dissertation/rest_arch_style.htm">original web programming model</a>, 162using <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/HATEOAS">Hypertext As The Engine Of Application State</a> 163without even needing to really understand that concept.</p> 164<p>Itâs worth mentioning that, if you prefer, you can use the <a rel="noopener" target="_blank" href="https://html.spec.whatwg.org/multipage/dom.html#attr-data-*"><code>data-</code></a> prefix when using htmx:</p> 165<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">data-hx-post</span><span>=</span><span style="color:#98c379;">"/click"</span><span>>Click Me!</</span><span style="color:#e06c75;">a</span><span>> 166</span></code></pre> 167<p>If you understand the concepts around htmx and want to see the quirks of the library, please see our 168<a href="https://htmx.org/quirks/">QUIRKS</a> page.</p> 169<h2 id="1-x-to-2-x-migration-guide"><a class="zola-anchor" href="#1-x-to-2-x-migration-guide" aria-label="Anchor link for: 1-x-to-2-x-migration-guide">
1691.x to 2.x Migration Guide</a></h2> 170<p><a rel="noopener" target="_blank" href="https://v1.htmx.org">Version 1</a> of htmx is still supported and supports IE11, but the latest version of htmx is 2.x.</p> 171<p>If you are migrating to htmx 2.x from <a rel="noopener" target="_blank" href="https://v1.htmx.org">htmx 1.x</a>, please see the <a href="https://htmx.org/migration-guide-htmx-1/">htmx 1.x migration guide</a>.</p> 172<p>If you are migrating to htmx from intercooler.js, please see the <a href="https://htmx.org/migration-guide-intercooler/">intercooler migration guide</a>.</p> 173<h2 id="installing"><a class="zola-anchor" href="#installing" aria-label="Anchor link for: installing">Installing</a></h2> 174<p>Htmx is a dependency-free, browser-oriented javascript library. This means that using it is as simple as adding a <code><script></code> 175tag to your document head. There is no need for a build system to use it.</p> 176<h3 id="via-a-cdn-e-g-jsdelivr"><a class="zola-anchor" href="#via-a-cdn-e-g-jsdelivr" aria-label="Anchor link for: via-a-cdn-e-g-jsdelivr">Via A CDN (e.g. jsDelivr)</a></h3> 177<p>The fastest way to get going with htmx is to load it via a CDN. You can simply add this to 178your head tag and get going:</p> 179<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">script </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js" </span><span style="color:#d19a66;">integrity</span><span>=</span><span style="color:#98c379;">"sha384-2OatzQy1H+Zd/IIrjr1TcuDGqLXeHhbooAyJY1KdQMKnr4LZ22k31GBLdYKHmVjg" </span><span style="color:#d19a66;">crossorigin</span><span>=</span><span style="color:#98c379;">"anonymous"</span><span>></</span><span style="color:#e06c75;">script</span><span>> 180</span></code></pre> 181<p>An unminified version is also available as well:</p> 182<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">script </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.js" </span><span style="color:#d19a66;">integrity</span><span>=</span><span style="color:#98c379;">"sha384-gmJEF2eAKY4e+FDN+qtKIivWyb6ANwDB7JUdUybKgQspPKyEX/pIRZG/0uaRoW2C" </span><span style="color:#d19a66;">crossorigin</span><span>=</span><span style="color:#98c379;">"anonymous"</span><span>></</span><span style="color:#e06c75;">script</span><span>> 183</span></code></pre> 184<p>While the CDN approach is extremely simple, you may want to consider 185<a rel="noopener" target="_blank" href="https://blog.wesleyac.com/posts/why-not-javascript-cdn">not using CDNs in production</a>.</p> 186<h3 id="download-a-copy"><a class="zola-anchor" href="#download-a-copy" aria-label="Anchor link for: download-a-copy">Download a copy</a></h3> 187<p>The next easiest way to install htmx is to simply copy it into your project.</p> 188<p>Download <code>htmx.min.js</code> <a rel="noopener" target="_blank" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js">from jsDelivr</a> and add it to the appropriate directory in your project 189and include it where necessary with a <code><script></code> tag:</p> 190<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">script </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"/path/to/htmx.min.js"</span><span>></</span><span style="color:#e06c75;">script</span><span>> 191</span></code></pre> 192<h3 id="npm"><a class="zola-anchor" href="#npm" aria-label="Anchor link for: npm">npm</a></h3> 193<p>For npm-style build systems, you can install htmx via <a rel="noopener" target="_blank" href="https://www.npmjs.com/">npm</a>:</p> 194<pre data-lang="sh" style="background-color:#1f2329;color:#abb2bf;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#e06c75;">npm</span><span> install [email protected] 195</span></code></pre> 196<p>After installing, youâll need to use appropriate tooling to use <code>node_modules/htmx.org/dist/htmx.js</code> (or <code>.min.js</code>). 197For example, you might bundle htmx with some extensions and project-specific code.</p> 198<h3 id="webpack"><a class="zola-anchor" href="#webpack" aria-label="Anchor link for: webpack">Webpack</a></h3> 199<p>If you are using webpack to manage your javascript:</p> 200<ul> 201<li>Install <code>htmx</code> via your favourite package manager (like npm or yarn)</li> 202<li>Add the import to your <code>index.js</code></li> 203</ul> 204<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#c678dd;">import </span><span style="color:#98c379;">'htmx.org'</span><span>; 205</span></code></pre> 206<p>If you want to use the global <code>htmx</code> variable (recommended), you need to inject it to the window scope:</p> 207<ul> 208<li>Create a custom JS file</li> 209<li>Import this file to your <code>index.js</code> (below the import from step 2)</li> 210</ul> 211<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#c678dd;">import </span><span style="color:#98c379;">'path/to/my_custom.js'</span><span>; 212</span></code></pre> 213<ul> 214<li>Then add this code to the file:</li> 215</ul> 216<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span>window.</span><span style="color:#e06c75;">htmx </span><span>= </span><span style="color:#56b6c2;">require</span><span>(</span><span style="color:#98c379;">'htmx.org'</span><span>); 217</span></code></pre> 218<ul> 219<li>Finally, rebuild your bundle</li> 220</ul> 221<h2 id="ajax"><a class="zola-anchor" href="#ajax" aria-label="Anchor link for: ajax">AJAX</a></h2> 222<p>The core of htmx is a set of attributes that allow you to issue AJAX requests directly from HTML:</p> 223<table><thead><tr><th>
223Attribute</th><th>Description</th></tr></thead><tbody> 224<tr><td><a href="https://htmx.org/attributes/hx-get/">hx-get</a></td><td>Issues a <code>GET</code> request to the given URL</td></tr> 225<tr><td><a href="https://htmx.org/attributes/hx-post/">hx-post</a></td><td>Issues a <code>POST</code> request to the given URL</td></tr> 226<tr><td><a href="https://htmx.org/attributes/hx-put/">hx-put</a></td><td>Issues a <code>PUT</code> request to the given URL</td></tr> 227<tr><td><a href="https://htmx.org/attributes/hx-patch/">hx-patch</a></td><td>Issues a <code>PATCH</code> request to the given URL</td></tr> 228<tr><td><a href="https://htmx.org/attributes/hx-delete/">hx-delete</a></td><td>Issues a <code>DELETE</code> request to the given URL</td></tr> 229</tbody></table> 230<p>Each of these attributes takes a URL to issue an AJAX request to. The element will issue a request of the specified 231type to the given URL when the element is <a href="https://htmx.org/docs/#triggers">triggered</a>:</p> 232<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-put</span><span>=</span><span style="color:#98c379;">"/messages"</span><span>> 233</span><span> Put To Messages 234</span><span></</span><span style="color:#e06c75;">button</span><span>> 235</span></code></pre> 236<p>This tells the browser:</p> 237<blockquote> 238<p>When a user clicks on this button, issue a PUT request to the URL /messages and load the response into the button</p> 239</blockquote> 240<h3 id="triggers"><a class="zola-anchor" href="#triggers" aria-label="Anchor link for: triggers">Triggering Requests</a></h3> 241<p>By default, AJAX requests are triggered by the ânaturalâ event of an element:</p> 242<ul> 243<li><code>input</code>, <code>textarea</code> & <code>select</code> are triggered on the <code>change</code> event</li> 244<li><code>form</code> is triggered on the <code>submit</code> event</li> 245<li>everything else is triggered by the <code>click</code> event</li> 246</ul> 247<p>If you want different behavior you can use the <a href="https://htmx.org/attributes/hx-trigger/">hx-trigger</a> 248attribute to specify which event will cause the request.</p> 249<p>Here is a <code>div</code> that posts to <code>/mouse_entered</code> when a mouse enters it:</p> 250<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/mouse_entered" </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"mouseenter"</span><span>> 251</span><span> [Here Mouse, Mouse!] 252</span><span></</span><span style="color:#e06c75;">div</span><span>> 253</span></code></pre> 254<h4 id="trigger-modifiers"><a class="zola-anchor" href="#trigger-modifiers" aria-label="Anchor link for: trigger-modifiers">Trigger Modifiers</a></h4> 255<p>A trigger can also have a few additional modifiers that change its behavior. For example, if you want a request to only 256happen once, you can use the <code>once</code> modifier for the trigger:</p> 257<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/mouse_entered" </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"mouseenter once"</span><span>> 258</span><span> [Here Mouse, Mouse!] 259</span><span></</span><span style="color:#e06c75;">div</span><span>> 260</span></code></pre> 261<p>Other modifiers you can use for triggers are:</p> 262<ul> 263<li><code>changed</code> - only issue a request if the value of the element has changed</li> 264<li><code>delay:<time interval></code> - wait the given amount of time (e.g. <code>1s</code>) before 265issuing the request. If the event triggers again, the countdown is reset.</li> 266<li><code>throttle:<time interval></code> - wait the given amount of time (e.g. <code>1s</code>) before 267issuing the request. Unlike <code>delay</code> if a new event occurs before the time limit is hit the event will be discarded, 268so the request will trigger at the end of the time period.</li> 269<li><code>from:<CSS Selector></code> - listen for the event on a different element. This can be used for things like keyboard shortcuts. Note that this CSS selector is not re-evaluated if the page changes.</li> 270</ul> 271<p>You can use these attributes to implement many common UX patterns, such as <a href="https://htmx.org/examples/active-search/">Active Search</a>:</p> 272<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"text" </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"q" 273</span><span> </span><span style="color:#d19a66;">
273hx-get</span><span>=</span><span style="color:#98c379;">"/trigger_delay" 274</span><span> </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"keyup changed delay:500ms" 275</span><span> </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#search-results" 276</span><span> </span><span style="color:#d19a66;">placeholder</span><span>=</span><span style="color:#98c379;">"Search..."</span><span>> 277</span><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"search-results"</span><span>></</span><span style="color:#e06c75;">div</span><span>> 278</span></code></pre> 279<p>This input will issue a request 500 milliseconds after a key up event if the input has been changed and inserts the results 280into the <code>div</code> with the id <code>search-results</code>.</p> 281<p>Multiple triggers can be specified in the <a href="https://htmx.org/attributes/hx-trigger/">hx-trigger</a> attribute, separated by commas.</p> 282<h4 id="trigger-filters"><a class="zola-anchor" href="#trigger-filters" aria-label="Anchor link for: trigger-filters">Trigger Filters</a></h4> 283<p>You may also apply trigger filters by using square brackets after the event name, enclosing a javascript expression that 284will be evaluated. If the expression evaluates to <code>true</code> the event will trigger, otherwise it will not.</p> 285<p>Here is an example that triggers only on a Control-Click of the element</p> 286<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/clicked" </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"click[ctrlKey]"</span><span>> 287</span><span> Control Click Me 288</span><span></</span><span style="color:#e06c75;">div</span><span>> 289</span></code></pre> 290<p>Properties like <code>ctrlKey</code> will be resolved against the triggering event first, then against the global scope. The 291<code>this</code> symbol will be set to the current element.</p> 292<h4 id="special-events"><a class="zola-anchor" href="#special-events" aria-label="Anchor link for: special-events">Special Events</a></h4> 293<p>htmx provides a few special events for use in <a href="https://htmx.org/attributes/hx-trigger/">hx-trigger</a>:</p> 294<ul> 295<li><code>load</code> - fires once when the element is first loaded</li> 296<li><code>revealed</code> - fires once when an element first scrolls into the viewport</li> 297<li><code>intersect</code> - fires once when an element first intersects the viewport. This supports two additional options: 298<ul> 299<li><code>root:<selector></code> - a CSS selector of the root element for intersection</li> 300<li><code>threshold:<float></code> - a floating point number between 0.0 and 1.0, indicating what amount of intersection to fire the event on</li> 301</ul> 302</li> 303</ul> 304<p>You can also use custom events to trigger requests if you have an advanced use case.</p> 305<h4 id="polling"><a class="zola-anchor" href="#polling" aria-label="Anchor link for: polling">Polling</a></h4> 306<p>If you want an element to poll the given URL rather than wait for an event, you can use the <code>every</code> syntax 307with the <a href="https://htmx.org/attributes/hx-trigger/"><code>hx-trigger</code></a> attribute:</p> 308<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/news" </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"every 2s"</span><span>></</span><span style="color:#e06c75;">div</span><span>> 309</span></code></pre> 310<p>This tells htmx</p> 311<blockquote> 312<p>Every 2 seconds, issue a GET to /news and load the response into the div</p> 313</blockquote> 314<p>If you want to stop polling from a server response you can respond with the HTTP response code <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/86_(term)"><code>286</code></a> 315and the element will cancel the polling.</p> 316<h4 id="load_polling"><a class="zola-anchor" href="#load_polling" aria-label="Anchor link for: load_polling">Load Polling</a></h4> 317<p>Another technique that can be used to achieve polling in htmx is âload pollingâ, where an element specifies 318a <code>load</code> trigger along with a delay, and replaces itself with the response:</p> 319<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">
319hx-get</span><span>=</span><span style="color:#98c379;">"/messages" 320</span><span> </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"load delay:1s" 321</span><span> </span><span style="color:#d19a66;">hx-swap</span><span>=</span><span style="color:#98c379;">"outerHTML"</span><span>> 322</span><span></</span><span style="color:#e06c75;">div</span><span>> 323</span></code></pre> 324<p>If the <code>/messages</code> end point keeps returning a div set up this way, it will keep âpollingâ back to the URL every 325second.</p> 326<p>Load polling can be useful in situations where a poll has an end point at which point the polling terminates, such as 327when you are showing the user a <a href="https://htmx.org/examples/progress-bar/">progress bar</a>.</p> 328<h3 id="indicators"><a class="zola-anchor" href="#indicators" aria-label="Anchor link for: indicators">Request Indicators</a></h3> 329<p>When an AJAX request is issued it is often good to let the user know that something is happening since the browser 330will not give them any feedback. You can accomplish this in htmx by using <code>htmx-indicator</code> class.</p> 331<p>The <code>htmx-indicator</code> class is defined so that the opacity of any element with this class is 0 by default, making it invisible 332but present in the DOM.</p> 333<p>When htmx issues a request, it will put a <code>htmx-request</code> class onto an element (either the requesting element or 334another element, if specified). The <code>htmx-request</code> class will cause a child element with the <code>htmx-indicator</code> class 335on it to transition to an opacity of 1, showing the indicator.</p> 336<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/click"</span><span>> 337</span><span> Click Me! 338</span><span> <</span><span style="color:#e06c75;">img </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"htmx-indicator" </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"/spinner.gif" </span><span style="color:#d19a66;">alt</span><span>=</span><span style="color:#98c379;">"Loading..."</span><span>> 339</span><span></</span><span style="color:#e06c75;">button</span><span>> 340</span></code></pre> 341<p>Here we have a button. When it is clicked the <code>htmx-request</code> class will be added to it, which will reveal the spinner 342gif element. (I like <a rel="noopener" target="_blank" href="http://samherbert.net/svg-loaders/">SVG spinners</a> these days.)</p> 343<p>While the <code>htmx-indicator</code> class uses opacity to hide and show the progress indicator, if you would prefer another mechanism 344you can create your own CSS transition like so:</p> 345<pre data-lang="css" style="background-color:#1f2329;color:#abb2bf;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#d19a66;">.htmx-indicator</span><span>{ 346</span><span> display:none; 347</span><span>} 348</span><span style="color:#d19a66;">.htmx-request .htmx-indicator</span><span>{ 349</span><span> display:inline; 350</span><span>} 351</span><span style="color:#d19a66;">.htmx-request.htmx-indicator</span><span>{ 352</span><span> display:inline; 353</span><span>} 354</span></code></pre> 355<p>If you want the <code>htmx-request</code> class added to a different element, you can use the <a href="https://htmx.org/attributes/hx-indicator/">hx-indicator</a> 356attribute with a CSS selector to do so:</p> 357<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div</span><span>> 358</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/click" </span><span style="color:#d19a66;">hx-indicator</span><span>=</span><span style="color:#98c379;">"#indicator"</span><span>> 359</span><span> Click Me! 360</span><span> </</span><span style="color:#e06c75;">button</span><span>> 361</span><span> <</span><span style="color:#e06c75;">img </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"indicator" </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"htmx-indicator" </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"/spinner.gif" </span><span style="color:#d19a66;">alt</span><span>=</span><span style="color:#98c379;">"Loading..."</span><span>/> 362</span><span></</span><span style="color:#e06c75;">div</span><span>> 363</span></code></pre> 364<p>Here we call out the indicator explicitly by id. Note that we could have placed the class on the parent <code>div</code> as well 365and had the same effect.</p> 366<p>You can also add the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled"><code>disabled</code> attribute</a> to 367elements for the duration of a request by using the <a href="https://htmx.org/attributes/hx-disabled-elt/">hx-disabled-elt</a> attribute.</p> 368<h3 id="targets"><a class="zola-anchor" href="#targets" aria-label="Anchor link for: targets">Targets</a></h3> 369<p>If you want the response to be loaded into a different element other than the one that made the request, you can 370use the <a href="https://htmx.org/attributes/hx-target/">hx-target</a>
370 attribute, which takes a CSS selector. Looking back at our Live Search example:</p> 371<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"text" </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"q" 372</span><span> </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/trigger_delay" 373</span><span> </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"keyup delay:500ms changed" 374</span><span> </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#search-results" 375</span><span> </span><span style="color:#d19a66;">placeholder</span><span>=</span><span style="color:#98c379;">"Search..."</span><span>> 376</span><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"search-results"</span><span>></</span><span style="color:#e06c75;">div</span><span>> 377</span></code></pre> 378<p>You can see that the results from the search are going to be loaded into <code>div#search-results</code>, rather than into the 379input tag.</p> 380<h4 id="extended-css-selectors"><a class="zola-anchor" href="#extended-css-selectors" aria-label="Anchor link for: extended-css-selectors">Extended CSS Selectors</a></h4> 381<p><code>hx-target</code>, and most attributes that take a CSS selector, support an âextendedâ CSS syntax:</p> 382<ul> 383<li>You can use the <code>this</code> keyword, which indicates that the element that the <code>hx-target</code> attribute is on is the target</li> 384<li>The <code>closest <CSS selector></code> syntax will find the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/docs/Web/API/Element/closest">closest</a> 385ancestor element or itself, that matches the given CSS selector. 386(e.g. <code>closest tr</code> will target the closest table row to the element)</li> 387<li>The <code>next <CSS selector></code> syntax will find the next element in the DOM matching the given CSS selector.</li> 388<li>The <code>previous <CSS selector></code> syntax will find the previous element in the DOM matching the given CSS selector.</li> 389<li><code>find <CSS selector></code> which will find the first child descendant element that matches the given CSS selector. 390(e.g <code>find tr</code> would target the first child descendant row to the element)</li> 391</ul> 392<p>In addition, a CSS selector may be wrapped in <code><</code> and <code>/></code> characters, mimicking the 393<a rel="noopener" target="_blank" href="https://hyperscript.org/expressions/query-reference/">query literal</a> syntax of hyperscript.</p> 394<p>Relative targets like this can be useful for creating flexible user interfaces without peppering your DOM with lots 395of <code>id</code> attributes.</p> 396<h3 id="swapping"><a class="zola-anchor" href="#swapping" aria-label="Anchor link for: swapping">Swapping</a></h3> 397<p>htmx offers a few different ways to swap the HTML returned into the DOM. By default, the content replaces the 398<code>innerHTML</code> of the target element. You can modify this by using the <a href="https://htmx.org/attributes/hx-swap/">hx-swap</a> attribute 399with any of the following values:</p> 400<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody> 401<tr><td><code>innerHTML</code></td><td>the default, puts the content inside the target element</td></tr> 402<tr><td><code>outerHTML</code></td><td>replaces the entire target element with the returned content</td></tr> 403<tr><td><code>afterbegin</code></td><td>prepends the content before the first child inside the target</td></tr> 404<tr><td><code>beforebegin</code></td><td>prepends the content before the target in the targetâs parent element</td></tr> 405<tr><td><code>beforeend</code></td><td>appends the content after the last child inside the target</td></tr> 406<tr><td><code>afterend</code></td><td>appends the content after the target in the targetâs parent element</td></tr> 407<tr><td><code>delete</code></td><td>deletes the target element regardless of the response</td></tr> 408<tr><td><code>none</code></td><td>
408does not append content from response (<a href="https://htmx.org/docs/#oob_swaps">Out of Band Swaps</a> and <a href="https://htmx.org/docs/#response-headers">Response Headers</a> will still be processed)</td></tr> 409</tbody></table> 410<h4 id="morphing"><a class="zola-anchor" href="#morphing" aria-label="Anchor link for: morphing">Morph Swaps</a></h4> 411<p>In addition to the standard swap mechanisms above, htmx also supports <em>morphing</em> swaps, via extensions. Morphing swaps 412attempt to <em>merge</em> new content into the existing DOM, rather than simply replacing it. They often do a better job 413preserving things like focus, video state, etc. by mutating existing nodes in-place during the swap operation, at the 414cost of more CPU.</p> 415<p>The following extensions are available for morph-style swaps:</p> 416<ul> 417<li><a href="/extensions/idiomorph">Idiomorph</a> - A morphing algorithm created by the htmx developers.</li> 418<li><a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx-extensions/blob/main/src/morphdom-swap/README.md">Morphdom Swap</a> - Based on the <a rel="noopener" target="_blank" href="https://github.com/patrick-steele-idem/morphdom">morphdom</a>, 419the original DOM morphing library.</li> 420<li><a rel="noopener" target="_blank" href="https://github.com/bigskysoftware/htmx-extensions/blob/main/src/alpine-morph/README.md">Alpine-morph</a> - Based on the <a rel="noopener" target="_blank" href="https://alpinejs.dev/plugins/morph">alpine morph</a> plugin, plays 421well with alpine.js</li> 422</ul> 423<h4 id="view-transitions"><a class="zola-anchor" href="#view-transitions" aria-label="Anchor link for: view-transitions">View Transitions</a></h4> 424<p>The new, experimental <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API">View Transitions API</a> 425gives developers a way to create an animated transition between different DOM states. It is still in active development 426and is not available in all browsers, but htmx provides a way to work with this new API that falls back to the non-transition 427mechanism if the API is not available in a given browser.</p> 428<p>You can experiment with this new API using the following approaches:</p> 429<ul> 430<li>Set the <code>htmx.config.globalViewTransitions</code> config variable to <code>true</code> to use transitions for all swaps</li> 431<li>Use the <code>transition:true</code> option in the <code>hx-swap</code> attribute</li> 432<li>If an element swap is going to be transitioned due to either of the above configurations, you may catch the 433<code>htmx:beforeTransition</code> event and call <code>preventDefault()</code> on it to cancel the transition.</li> 434</ul> 435<p>View Transitions can be configured using CSS, as outlined in <a rel="noopener" target="_blank" href="https://developer.chrome.com/docs/web-platform/view-transitions/#simple-customization">the Chrome documentation for the feature</a>.</p> 436<p>You can see a view transition example on the <a href="/examples/animations#view-transitions">Animation Examples</a> page.</p> 437<h4 id="swap-options"><a class="zola-anchor" href="#swap-options" aria-label="Anchor link for: swap-options">Swap Options</a></h4> 438<p>The <a href="https://htmx.org/attributes/hx-swap/">hx-swap</a> attribute supports many options for tuning the swapping behavior of htmx. For 439example, by default htmx will swap in the title of a title tag found anywhere in the new content. You can turn this 440behavior off by setting the <code>ignoreTitle</code> modifier to true:</p> 441<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/like" </span><span style="color:#d19a66;">hx-swap</span><span>=</span><span style="color:#98c379;">"outerHTML ignoreTitle:true"</span><span>>Like</</span><span style="color:#e06c75;">button</span><span>> 442</span></code></pre> 443<p>The modifiers available on <code>hx-swap</code> are:</p> 444<table><thead><tr><th>
444Option</th><th>Description</th></tr></thead><tbody> 445<tr><td><code>transition</code></td><td><code>true</code> or <code>false</code>, whether to use the view transition API for this swap</td></tr> 446<tr><td><code>swap</code></td><td>The swap delay to use (e.g. <code>100ms</code>) between when old content is cleared and the new content is inserted</td></tr> 447<tr><td><code>settle</code></td><td>The settle delay to use (e.g. <code>100ms</code>) between when new content is inserted and when it is settled</td></tr> 448<tr><td><code>ignoreTitle</code></td><td>If set to <code>true</code>, any title found in the new content will be ignored and not update the document title</td></tr> 449<tr><td><code>scroll</code></td><td><code>top</code> or <code>bottom</code>, will scroll the target element to its top or bottom</td></tr> 450<tr><td><code>show</code></td><td><code>top</code> or <code>bottom</code>, will scroll the target elementâs top or bottom into view</td></tr> 451</tbody></table> 452<p>All swap modifiers appear after the swap style is specified, and are colon-separated.</p> 453<p>See the <a href="https://htmx.org/attributes/hx-swap/">hx-swap</a> documentation for more details on these options.</p> 454<h3 id="synchronization"><a class="zola-anchor" href="#synchronization" aria-label="Anchor link for: synchronization">Synchronization</a></h3> 455<p>Often you want to coordinate the requests between two elements. For example, you may want a request from one element 456to supersede the request of another element, or to wait until the other elementâs request has finished.</p> 457<p>htmx offers a <a href="https://htmx.org/attributes/hx-sync/"><code>hx-sync</code></a> attribute to help you accomplish this.</p> 458<p>Consider a race condition between a form submission and an individual inputâs validation request in this HTML:</p> 459<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/store"</span><span>> 460</span><span> <</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"title" </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"title" </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"text" 461</span><span> </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/validate" 462</span><span> </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"change"</span><span>> 463</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"submit"</span><span>>Submit</</span><span style="color:#e06c75;">button</span><span>> 464</span><span></</span><span style="color:#e06c75;">form</span><span>> 465</span></code></pre> 466<p>Without using <code>hx-sync</code>, filling out the input and immediately submitting the form triggers two parallel requests to 467<code>/validate</code> and <code>/store</code>.</p> 468<p>Using <code>hx-sync="closest form:abort"</code> on the input will watch for requests on the form and abort the inputâs request if 469a form request is present or starts while the input request is in flight:</p> 470<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/store"</span><span>> 471</span><span> <</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"title" </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"title" </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"text" 472</span><span> </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/validate" 473</span><span> </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"change" 474</span><span> </span><span style="color:#d19a66;">hx-sync</span><span>=</span><span style="color:#98c379;">"closest form:abort"</span><span>> 475</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"submit"</span><span>>Submit</</span><span style="color:#e06c75;">button</span><span>> 476</span><span></</span><span style="color:#e06c75;">form</span><span>> 477</span></code></pre> 478<p>This resolves the synchronization between the two elements in a declarative way.</p> 479<p>htmx also supports a programmatic way to cancel requests: you can send the <code>htmx:abort</code> event to an element to 480cancel any in-flight requests:</p> 481<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"request-button" </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/example"</span><span>> 482</span><span> Issue Request 483</span><span></</span><span style="color:#e06c75;">button</span><span>> 484</span><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">onclick</span><span>=</span><span style="color:#98c379;">"</span><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#e06c75;">trigger</span><span>(</span><span style="color:#98c379;">'#request-button'</span><span>, </span><span style="color:#98c379;">'htmx:abort'</span><span>)</span><span style="color:#98c379;">"</span><span>> 485</span><span> Cancel Request 486</span><span></</span><span style="color:#e06c75;">button</span><span>> 487</span></code></pre> 488<p>More examples and details can be found on the <a href="https://htmx.org/attributes/hx-sync/"><code>hx-sync</code> attribute page.</a></p> 489<h3 id="css_transitions"><a class="zola-anchor" href="#css_transitions" aria-label="Anchor link for: css_transitions">CSS Transitions</a></h3> 490<p>htmx makes it easy to use <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions">CSS Transitions</a> without 491javascript. Consider this HTML content:</p> 492<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"div1"</span><span>>Original Content</</span><span style="color:#e06c75;">div</span><span>> 493</span></code></pre> 494<p>Imagine this content is replaced by htmx via an ajax request with this new content:</p> 495<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"div1" </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"red"</span><span>>New Content</</span><span style="color:#e06c75;">div</span><span>> 496</span></code></pre> 497<p>Note two things:</p> 498<ul> 499<li>The div has the <em>
499same</em> id in the original and in the new content</li> 500<li>The <code>red</code> class has been added to the new content</li> 501</ul> 502<p>Given this situation, we can write a CSS transition from the old state to the new state:</p> 503<pre data-lang="css" style="background-color:#1f2329;color:#abb2bf;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#d19a66;">.red </span><span>{ 504</span><span> color: red; 505</span><span> transition: all ease-in </span><span style="color:#d19a66;">1s </span><span>; 506</span><span>} 507</span></code></pre> 508<p>When htmx swaps in this new content, it will do so in such a way that the CSS transition will apply to the new content, 509giving you a nice, smooth transition to the new state.</p> 510<p>So, in summary, all you need to do to use CSS transitions for an element is keep its <code>id</code> stable across requests!</p> 511<p>You can see the <a href="https://htmx.org/examples/animations/">Animation Examples</a> for more details and live demonstrations.</p> 512<h4 id="details"><a class="zola-anchor" href="#details" aria-label="Anchor link for: details">Details</a></h4> 513<p>To understand how CSS transitions actually work in htmx, you must understand the underlying swap & settle model that htmx uses.</p> 514<p>When new content is received from a server, before the content is swapped in, the existing 515content of the page is examined for elements that match by the <code>id</code> attribute. If a match 516is found for an element in the new content, the attributes of the old content are copied 517onto the new element before the swap occurs. The new content is then swapped in, but with the 518<em>old</em> attribute values. Finally, the new attribute values are swapped in, after a âsettleâ delay 519(20ms by default). A little crazy, but this is what allows CSS transitions to work without any javascript by 520the developer.</p> 521<h3 id="oob_swaps"><a class="zola-anchor" href="#oob_swaps" aria-label="Anchor link for: oob_swaps">Out of Band Swaps</a></h3> 522<p>If you want to swap content from a response directly into the DOM by using the <code>id</code> attribute you can use the 523<a href="https://htmx.org/attributes/hx-swap-oob/">hx-swap-oob</a> attribute in the <em>response</em> html:</p> 524<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"message" </span><span style="color:#d19a66;">hx-swap-oob</span><span>=</span><span style="color:#98c379;">"true"</span><span>>Swap me directly!</</span><span style="color:#e06c75;">div</span><span>> 525</span><span>Additional Content 526</span></code></pre> 527<p>In this response, <code>div#message</code> would be swapped directly into the matching DOM element, while the additional content 528would be swapped into the target in the normal manner.</p> 529<p>You can use this technique to âpiggy-backâ updates on other requests.</p> 530<h4 id="troublesome-tables"><a class="zola-anchor" href="#troublesome-tables" aria-label="Anchor link for: troublesome-tables">Troublesome Tables</a></h4> 531<p>Table elements can be problematic when combined with out of band swaps, because, by the HTML spec, many canât stand on 532their own in the DOM (e.g. <code><tr></code> or <code><td></code>).</p> 533<p>To avoid this issue you can use a <code>template</code> tag to encapsulate these elements:</p> 534<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">template</span><span>> 535</span><span> <</span><span style="color:#e06c75;">tr </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"message" </span><span style="color:#d19a66;">hx-swap-oob</span><span>=</span><span style="color:#98c379;">"true"</span><span>><</span><span style="color:#e06c75;">td</span><span>>Joe</</span><span style="color:#e06c75;">td</span><span>><</span><span style="color:#e06c75;">td</span><span>>Smith</</span><span style="color:#e06c75;">td</span><span>></</span><span style="color:#e06c75;">tr</span><span>> 536</span><span></</span><span style="color:#e06c75;">template</span><span>> 537</span></code></pre> 538<h4 id="partial_swaps"><a class="zola-anchor" href="#partial_swaps" aria-label="Anchor link for: partial_swaps">Server-Sent Partial Swap Commands</a></h4> 539<p>For more complex responses that need to update multiple parts of the page, htmx supports 540<a href="https://htmx.org/attributes/hx-partial/"><code><hx-partial></code></a> â a server-sent swap command format. The server 541wraps content in <code><hx-partial hx-target="..."></code> tags; htmx reads the targeting instructions, 542performs the swaps, and discards the envelope entirely. Nothing from the tag itself ever 543appears in the page.</p> 544<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div</span><span>>Updated main content</</span><span style="color:#e06c75;">div</span><span>> 545</span><span> 546</span><span><</span><span style="color:#e06c75;">hx-partial </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#cart-count"</span><span>>3</</span><span style="color:#e06c75;">
546hx-partial</span><span>> 547</span><span><</span><span style="color:#e06c75;">hx-partial </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#cart-total"</span><span>>$29.97</</span><span style="color:#e06c75;">hx-partial</span><span>> 548</span></code></pre> 549<p>Like <code>hx-swap-oob</code>, partials execute <strong>before</strong> the main swap and targets are resolved 550relative to the triggering element using the full <a href="https://htmx.org/docs/#extended-css-selectors">extended CSS selector</a> 551vocabulary (<code>closest</code>, <code>find</code>, <code>next</code>, <code>previous</code>, etc.).</p> 552<p>See the <a href="https://htmx.org/attributes/hx-partial/"><code>hx-partial</code> documentation</a> for full details.</p> 553<h4 id="selecting-content-to-swap"><a class="zola-anchor" href="#selecting-content-to-swap" aria-label="Anchor link for: selecting-content-to-swap">Selecting Content To Swap</a></h4> 554<p>If you want to select a subset of the response HTML to swap into the target, you can use the <a href="https://htmx.org/attributes/hx-select/">hx-select</a>
555attribute, which takes a CSS selector and selects the matching elements from the response.</p> 556<p>You can also pick out pieces of content for an out-of-band swap by using the <a href="https://htmx.org/attributes/hx-select-oob/">hx-select-oob</a> 557attribute, which takes a list of element IDs to pick out and swap.</p> 558<h4 id="preserving-content-during-a-swap"><a class="zola-anchor" href="#preserving-content-during-a-swap" aria-label="Anchor link for: preserving-content-during-a-swap">Preserving Content During A Swap</a></h4> 559<p>If there is content that you wish to be preserved across swaps (e.g. a video player that you wish to remain playing 560even if a swap occurs) you can use the <a href="https://htmx.org/attributes/hx-preserve/">hx-preserve</a> 561attribute on the elements you wish to be preserved.</p> 562<h3 id="parameters"><a class="zola-anchor" href="#parameters" aria-label="Anchor link for: parameters">Parameters</a></h3> 563<p>By default, an element that causes a request will include its value if it has one. If the element is a form it 564will include the values of all inputs within it.</p> 565<p>As with HTML forms, the <code>name</code> attribute of the input is used as the parameter name in the request that htmx sends.</p> 566<p>Additionally, if the element causes a non-<code>GET</code> request, the values of all the inputs of the associated form will be 567included (typically this is the nearest enclosing form, but could be different if e.g. <code><button form="associated-form"></code> is used).</p> 568<p>If you wish to include the values of other elements, you can use the <a href="https://htmx.org/attributes/hx-include/">hx-include</a> attribute 569with a CSS selector of all the elements whose values you want to include in the request.</p> 570<p>If you wish to filter out some parameters you can use the <a href="https://htmx.org/attributes/hx-params/">hx-params</a> attribute.</p> 571<p>Finally, if you want to programmatically modify the parameters, you can use the <a href="https://htmx.org/events/#htmx:configRequest">htmx:configRequest</a> 572event.</p> 573<h4 id="files"><a class="zola-anchor" href="#files" aria-label="Anchor link for: files">File Upload</a></h4> 574<p>If you wish to upload files via an htmx request, you can set the <a href="https://htmx.org/attributes/hx-encoding/">hx-encoding</a> attribute to 575<code>multipart/form-data</code>. This will use a <code>FormData</code> object to submit the request, which will properly include the file 576in the request.</p> 577<p>Note that depending on your server-side technology, you may have to handle requests with this type of body content very 578differently.</p> 579<p>Note that htmx fires a <code>htmx:xhr:progress</code> event periodically based on the standard <code>progress</code> event during upload, 580which you can hook into to show the progress of the upload.</p> 581<p>See the <a href="https://htmx.org/examples/">examples section</a> for more advanced form patterns, including <a href="https://htmx.org/examples/file-upload/">progress bars</a> and <a href="https://htmx.org/examples/file-upload-input/">error handling</a>.</p> 582<h4 id="extra-values"><a class="zola-anchor" href="#extra-values" aria-label="Anchor link for: extra-values">Extra Values</a></h4> 583<p>You can include extra values in a request using the <a href="https://htmx.org/attributes/hx-vals/">hx-vals</a> (name-expression pairs in JSON format) and 584<a href="https://htmx.org/attributes/hx-vars/">hx-vars</a> attributes (comma-separated name-expression pairs that are dynamically computed).</p> 585<h3 id="confirming"><a class="zola-anchor" href="#confirming" aria-label="Anchor link for: confirming">Confirming Requests</a></h3> 586<p>Often you will want to confirm an action before issuing a request. htmx supports the <a href="https://htmx.org/attributes/hx-confirm/"><code>hx-confirm</code></a> 587attribute, which allows you to confirm an action using a simple javascript dialog:</p> 588<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-delete</span><span>=</span><span style="color:#98c379;">"/account" </span><span style="color:#d19a66;">hx-confirm</span><span>=</span><span style="color:#98c379;">"Are you sure you wish to delete your account?"</span><span>> 589</span><span>
589 Delete My Account 590</span><span></</span><span style="color:#e06c75;">button</span><span>> 591</span></code></pre> 592<p>Using events you can implement more sophisticated confirmation dialogs. The <a href="https://htmx.org/examples/confirm/">confirm example</a> 593shows how to use <a rel="noopener" target="_blank" href="https://sweetalert2.github.io/">sweetalert2</a> library for confirmation of htmx actions.</p> 594<h4 id="confirming-requests-using-events"><a class="zola-anchor" href="#confirming-requests-using-events" aria-label="Anchor link for: confirming-requests-using-events">Confirming Requests Using Events</a></h4> 595<p>Another option to do confirmation with is via the <a href="https://htmx.org/events/#htmx:confirm"><code>htmx:confirm</code> event</a>. This event 596is fired on <em>every</em> trigger for a request (not just on elements that have a <code>hx-confirm</code> attribute) and can be used 597to implement asynchronous confirmation of the request.</p> 598<p>Here is an example using <a rel="noopener" target="_blank" href="https://sweetalert.js.org/guides/">sweet alert</a> on any element with a <code>confirm-with-sweet-alert='true'</code> attribute on it:</p> 599<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span>document.body.</span><span style="color:#56b6c2;">addEventListener</span><span>(</span><span style="color:#98c379;">'htmx:confirm'</span><span>, </span><span style="color:#c678dd;">function</span><span>(</span><span style="color:#e06c75;">evt</span><span>) { 600</span><span> </span><span style="color:#c678dd;">if </span><span>(</span><span style="color:#e06c75;">evt</span><span>.target.</span><span style="color:#56b6c2;">matches</span><span>(</span><span style="color:#98c379;">"[confirm-with-sweet-alert='true']"</span><span>)) { 601</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#56b6c2;">preventDefault</span><span>(); 602</span><span> </span><span style="color:#61afef;">swal</span><span>({ 603</span><span> title: </span><span style="color:#98c379;">"Are you sure?"</span><span>, 604</span><span> text: </span><span style="color:#98c379;">"Are you sure you are sure?"</span><span>, 605</span><span> icon: </span><span style="color:#98c379;">"warning"</span><span>, 606</span><span> buttons: </span><span style="color:#d19a66;">true</span><span>, 607</span><span> dangerMode: </span><span style="color:#d19a66;">true</span><span>, 608</span><span> }).</span><span style="color:#56b6c2;">then</span><span>((</span><span style="color:#e06c75;">confirmed</span><span>) </span><span style="color:#c678dd;">=> </span><span>{ 609</span><span> </span><span style="color:#c678dd;">if </span><span>(</span><span style="color:#e06c75;">confirmed</span><span>) { 610</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#61afef;">issueRequest</span><span>(); 611</span><span> } 612</span><span> }); 613</span><span> } 614</span><span>}); 615</span></code></pre> 616<h2 id="inheritance"><a class="zola-anchor" href="#inheritance" aria-label="Anchor link for: inheritance">Attribute Inheritance</a></h2> 617<p>Most attributes in htmx are inherited: they apply to the element they are on as well as any children elements. This 618allows you to âhoistâ attributes up the DOM to avoid code duplication. Consider the following htmx:</p> 619<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-delete</span><span>=</span><span style="color:#98c379;">"/account" </span><span style="color:#d19a66;">hx-confirm</span><span>=</span><span style="color:#98c379;">"Are you sure?"</span><span>> 620</span><span> Delete My Account 621</span><span></</span><span style="color:#e06c75;">button</span><span>> 622</span><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-put</span><span>=</span><span style="color:#98c379;">"/account" </span><span style="color:#d19a66;">hx-confirm</span><span>=</span><span style="color:#98c379;">"Are you sure?"</span><span>> 623</span><span> Update My Account 624</span><span></</span><span style="color:#e06c75;">button</span><span>> 625</span></code></pre> 626<p>Here we have a duplicate <code>hx-confirm</code> attribute. We can hoist this attribute to a parent element:</p> 627<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-confirm</span><span>=</span><span style="color:#98c379;">"Are you sure?"</span><span>> 628</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-delete</span><span>=</span><span style="color:#98c379;">"/account"</span><span>> 629</span><span>
629 Delete My Account 630</span><span> </</span><span style="color:#e06c75;">button</span><span>> 631</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-put</span><span>=</span><span style="color:#98c379;">"/account"</span><span>> 632</span><span> Update My Account 633</span><span> </</span><span style="color:#e06c75;">button</span><span>> 634</span><span></</span><span style="color:#e06c75;">div</span><span>> 635</span></code></pre> 636<p>This <code>hx-confirm</code> attribute will now apply to all htmx-powered elements within it.</p> 637<p>Sometimes you wish to undo this inheritance. Consider if we had a cancel button to this group, but didnât want it to 638be confirmed. We could add an <code>unset</code> directive on it like so:</p> 639<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-confirm</span><span>=</span><span style="color:#98c379;">"Are you sure?"</span><span>> 640</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-delete</span><span>=</span><span style="color:#98c379;">"/account"</span><span>> 641</span><span> Delete My Account 642</span><span> </</span><span style="color:#e06c75;">button</span><span>> 643</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-put</span><span>=</span><span style="color:#98c379;">"/account"</span><span>> 644</span><span> Update My Account 645</span><span> </</span><span style="color:#e06c75;">button</span><span>> 646</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-confirm</span><span>=</span><span style="color:#98c379;">"unset" </span><span style="color:#d19a66;">hx-get</span><span>=</span><span style="color:#98c379;">"/"</span><span>> 647</span><span> Cancel 648</span><span> </</span><span style="color:#e06c75;">button</span><span>> 649</span><span></</span><span style="color:#e06c75;">div</span><span>> 650</span></code></pre> 651<p>The top two buttons would then show a confirm dialog, but the bottom cancel button would not.</p> 652<p>Inheritance can be disabled on a per-element and per-attribute basis using the 653<a href="https://htmx.org/attributes/hx-disinherit/"><code>hx-disinherit</code></a> attribute.</p> 654<p>If you wish to disable attribute inheritance entirely, you can set the <code>htmx.config.disableInheritance</code> configuration 655variable to <code>true</code>. This will disable inheritance as a default, and allow you to specify inheritance explicitly 656with the <a href="https://htmx.org/attributes/hx-inherit/"><code>hx-inherit</code></a> attribute.</p> 657<h2 id="boosting"><a class="zola-anchor" href="#boosting" aria-label="Anchor link for: boosting">Boosting</a></h2> 658<p>Htmx supports âboostingâ regular HTML anchors and forms with the <a href="https://htmx.org/attributes/hx-boost/">hx-boost</a> attribute. This 659attribute will convert all anchor tags and forms into AJAX requests that, by default, target the body of the page.</p> 660<p>Here is an example:</p> 661<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-boost</span><span>=</span><span style="color:#98c379;">"true"</span><span>> 662</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"/blog"</span><span>>Blog</</span><span style="color:#e06c75;">a</span><span>> 663</span><span></</span><span style="color:#e06c75;">div</span><span>> 664</span></code></pre> 665<p>The anchor tag in this div will issue an AJAX <code>GET</code> request to <code>/blog</code> and swap the response into the <code>body</code> tag.</p> 666<h3 id="progressive_enhancement"><a class="zola-anchor" href="#progressive_enhancement" aria-label="Anchor link for: progressive_enhancement">Progressive Enhancement</a></h3> 667<p>A feature of <code>hx-boost</code> is that it degrades gracefully if javascript is not enabled: the links and forms continue 668to work, they simply donât use ajax requests. This is known as 669<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement">Progressive Enhancement</a>, and it allows 670a wider audience to use your siteâs functionality.</p> 671<p>Other htmx patterns can be adapted to achieve progressive enhancement as well, but they will require more thought.</p> 672<p>Consider the <a href="https://htmx.org/examples/active-search/">active search</a> example. As it is written, it will not degrade gracefully: 673someone who does not have javascript enabled will not be able to use this feature. This is done for simplicityâs sake, 674to keep the example as brief as possible.</p> 675<p>However, you could wrap the htmx-enhanced input in a form element:</p> 676<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">action</span><span>=</span><span style="color:#98c379;">"/search" </span><span style="color:#d19a66;">method</span><span>=</span><span style="color:#98c379;">"POST"</span><span>> 677</span><span> <</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"form-control" </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">"search" 678</span><span> </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"search" </span><span style="color:#d19a66;">placeholder</span><span>=</span><span style="color:#98c379;">"Begin typing to search users..." 679</span><span> </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/search" 680</span><span> </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"keyup changed delay:500ms, search" 681</span><span> </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#search-results" 682</span><span> </span><span style="color:#d19a66;">hx-indicator</span><span>=</span><span style="color:#98c379;">".htmx-indicator"</span><span>> 683</span><span></</span><span style="color:#e06c75;">form</span><span>> 684</span></code></pre> 685<p>With this in place, javascript-enabled clients would still get the nice active-search UX, but non-javascript enabled 686clients would be able to hit the enter key and still search. Even better, you could add a âSearchâ button as well. 687You would then need to update the form with an <code>hx-post</code> that mirrored the <code>action</code> attribute, or perhaps use <code>hx-boost</code> 688on it.</p> 689<p>You would need to check on the server side for the <code>HX-Request</code> header to differentiate between an htmx-driven and a 690regular request, to determine exactly what to render to the client.</p> 691<p>Other patterns can be adapted similarly to achieve the progressive enhancement needs of your application.</p> 692<p>As you can see, this requires more thought and more work. It also rules some functionality entirely out of bounds. 693These tradeoffs must be made by you, the developer, with respect to your projects goals and audience.</p> 694<p><a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility">Accessibility</a> is a concept 695closely related to progressive enhancement. Using progressive enhancement techniques such as <code>hx-boost</code> will make your 696htmx application more accessible to a wide array of users.</p> 697<p>htmx-based applications are very similar to normal, non-AJAX driven web applications because htmx is HTML-oriented.</p> 698<p>As such, the normal HTML accessibility recommendations apply. For example:</p> 699<ul> 700<li>Use semantic HTML as much as possible (i.e. the right tags for the right things)</li> 701<li>Ensure focus state is clearly visible</li> 702<li>Associate text labels with all form fields</li> 703<li>Maximize the readability of your application with appropriate fonts, contrast, etc.</li> 704</ul> 705<h2 id="websockets-and-sse"><a class="zola-anchor" href="#websockets-and-sse" aria-label="Anchor link for: websockets-and-sse">Web Sockets & SSE</a></h2> 706<p>Web Sockets and Server Sent Events (SSE) are supported via extensions. Please see 707the <a href="/extensions/sse">SSE extension</a> and <a href="/extensions/ws">WebSocket extension</a> 708pages to learn more.</p> 709<h2 id="history"><a class="zola-anchor" href="#history" aria-label="Anchor link for: history">History Support</a></h2> 710<p>Htmx provides a simple mechanism for interacting with the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/History_API">browser history API</a>:</p> 711<p>If you want a given element to push its request URL into the browser navigation bar and add the current state of the page 712to the browserâs history, include the <a href="https://htmx.org/attributes/hx-push-url/">hx-push-url</a> attribute:</p> 713<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">
713hx-get</span><span>=</span><span style="color:#98c379;">"/blog" </span><span style="color:#d19a66;">hx-push-url</span><span>=</span><span style="color:#98c379;">"true"</span><span>>Blog</</span><span style="color:#e06c75;">a</span><span>> 714</span></code></pre> 715<p>When a user clicks on this link, htmx will snapshot the current DOM and store it before it makes a request to /blog. 716It then does the swap and pushes a new location onto the history stack.</p> 717<p>When a user hits the back button, htmx will retrieve the old content from storage and swap it back into the target, 718simulating âgoing backâ to the previous state. If the location is not found in the cache, htmx will make an ajax 719request to the given URL, with the header <code>HX-History-Restore-Request</code> set to true, and expects back the HTML needed 720for the entire page. You should always set <code>htmx.config.historyRestoreAsHxRequest</code> to false to prevent the <code>HX-Request</code> header 721which can then be safely used to respond with partials. Alternatively, if the <code>htmx.config.refreshOnHistoryMiss</code> config variable 722is set to true, it will issue a hard browser refresh.</p> 723<p><strong>NOTE:</strong> If you push a URL into the history, you <strong>must</strong> be able to navigate to that URL and get a full page back! 724A user could copy and paste the URL into an email, or new tab. Additionally, htmx will need the entire page when restoring 725history if the page is not in the history cache.</p> 726<h3 id="specifying-history-snapshot-element"><a class="zola-anchor" href="#specifying-history-snapshot-element" aria-label="Anchor link for: specifying-history-snapshot-element">Specifying History Snapshot Element</a></h3> 727<p>By default, htmx will use the <code>body</code> to take and restore the history snapshot from. This is usually the right thing, but 728if you want to use a narrower element for snapshotting you can use the <a href="https://htmx.org/attributes/hx-history-elt/">hx-history-elt</a> 729attribute to specify a different one.</p> 730<p>Careful: this element will need to be on all pages or restoring from history wonât work reliably.</p> 731<h3 id="undoing-dom-mutations-by-3rd-party-libraries"><a class="zola-anchor" href="#undoing-dom-mutations-by-3rd-party-libraries" aria-label="Anchor link for: undoing-dom-mutations-by-3rd-party-libraries">Undoing DOM Mutations By 3rd Party Libraries</a></h3> 732<p>If you are using a 3rd party library and want to use the htmx history feature, you will need to clean up the DOM before 733a snapshot is taken. Letâs consider the <a rel="noopener" target="_blank" href="https://tom-select.js.org/">Tom Select</a> library, which makes select elements 734a much richer user experience. Letâs set up TomSelect to turn any input element with the <code>.tomselect</code> class into a rich 735select element.</p> 736<p>First we need to initialize elements that have the class in new content:</p> 737<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#56b6c2;">onLoad</span><span>(</span><span style="color:#c678dd;">function </span><span>(</span><span style="color:#e06c75;">target</span><span>) { 738</span><span> </span><span style="font-style:italic;color:#848da1;">// find all elements in the new content that should be 739</span><span> </span><span style="font-style:italic;color:#848da1;">// an editor and init w/ TomSelect 740</span><span> </span><span style="color:#c678dd;">var </span><span style="color:#e06c75;">editors </span><span>= </span><span style="color:#e06c75;">target</span><span>.</span><span style="color:#56b6c2;">querySelectorAll</span><span>(</span><span style="color:#98c379;">".tomselect"</span><span>) 741</span><span> .</span><span style="color:#56b6c2;">forEach</span><span>(</span><span style="color:#e06c75;">elt </span><span style="color:#c678dd;">=> </span><span>new TomSelect(</span><span style="color:#e06c75;">elt</span><span>)) 742</span><span>}); 743</span></code></pre> 744<p>This will create a rich selector for all input elements that have the <code>.tomselect</code> class on it. However, it mutates 745the DOM and we donât want that mutation saved to the history cache, since TomSelect will be reinitialized when the 746history content is loaded back into the screen.</p> 747<p>To deal with this, we need to catch the <code>htmx:beforeHistorySave</code> event and clean out the TomSelect mutations by calling 748<code>destroy()</code> on them:</p> 749<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#61afef;">on</span><span>(</span><span style="color:#98c379;">'htmx:beforeHistorySave'</span><span>, </span><span style="color:#c678dd;">function</span><span>() { 750</span><span> </span><span style="font-style:italic;color:#848da1;">// find all TomSelect elements 751</span><span> document.</span><span style="color:#56b6c2;">querySelectorAll</span><span>(</span><span style="color:#98c379;">'.tomSelect'</span><span>) 752</span><span> .</span><span style="color:#56b6c2;">forEach</span><span>(</span><span style="color:#e06c75;">elt </span><span style="color:#c678dd;">=> </span><span style="color:#e06c75;">elt</span><span>.</span><span style="color:#e06c75;">tomselect</span><span>.</span><span style="color:#61afef;">destroy</span><span>()) </span><span style="font-style:italic;color:#848da1;">// and call destroy() on them 753</span><span>}) 754</span></code></pre> 755<p>This will revert the DOM to the original HTML, thus allowing for a clean snapshot.</p> 756<h3 id="disabling-history-snapshots"><a class="zola-anchor" href="#disabling-history-snapshots" aria-label="Anchor link for: disabling-history-snapshots">Disabling History Snapshots</a></h3> 757<p>History snapshotting can be disabled for a URL by setting the <a href="https://htmx.org/attributes/hx-history/">hx-history</a> attribute to <code>false</code> 758on any element in the current document, or any html fragment loaded into the current document by htmx. This can be used
759to prevent sensitive data entering the localStorage cache, which can be important for shared-use / public computers. 760History navigation will work as expected, but on restoration the URL will be requested from the server instead of the 761local history cache.</p> 762<h2 id="requests"><a class="zola-anchor" href="#requests" aria-label="Anchor link for: requests">Requests & Responses</a></h2> 763<p>Htmx expects responses to the AJAX requests it makes to be HTML, typically HTML fragments (although a full HTML 764document, matched with a <a href="https://htmx.org/attributes/hx-select/">hx-select</a> tag can be useful too). Htmx will then swap the returned 765HTML into the document at the target specified and with the swap strategy specified.</p> 766<p>Sometimes you might want to do nothing in the swap, but still perhaps trigger a client side event (<a href="https://htmx.org/docs/#response-headers">see below</a>).</p> 767<p>For this situation, by default, you can return a <code>204 - No Content</code> response code, and htmx will ignore the content of 768the response.</p> 769<p>In the event of an error response from the server (e.g. a 404 or a 501), htmx will trigger the <a href="https://htmx.org/events/#htmx:responseError"><code>htmx:responseError</code></a> 770event, which you can handle.</p> 771<p>In the event of a connection error, the <a href="https://htmx.org/events/#htmx:sendError"><code>htmx:sendError</code></a> event will be triggered.</p> 772<h3 id="response-handling"><a class="zola-anchor" href="#response-handling" aria-label="Anchor link for: response-handling">Configuring Response Handling</a></h3> 773<p>You can configure the above behavior of htmx by mutating or replacing the <code>htmx.config.responseHandling</code> array. This 774object is a collection of JavaScript objects defined like so:</p> 775<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span> responseHandling: [ 776</span><span> {code:</span><span style="color:#98c379;">"204"</span><span>, swap: </span><span style="color:#d19a66;">false</span><span>}, </span><span style="font-style:italic;color:#848da1;">// 204 - No Content by default does nothing, but is not an error 777</span><span> {code:</span><span style="color:#98c379;">"[23].."</span><span>, swap: </span><span style="color:#d19a66;">true</span><span>}, </span><span style="font-style:italic;color:#848da1;">// 200 & 300 responses are non-errors and are swapped 778</span><span> {code:</span><span style="color:#98c379;">"[45].."</span><span>, swap: </span><span style="color:#d19a66;">false</span><span>, error:</span><span style="color:#d19a66;">true</span><span>}, </span><span style="font-style:italic;color:#848da1;">// 400 & 500 responses are not swapped and are errors 779</span><span> {code:</span><span style="color:#98c379;">"..."</span><span>, swap: </span><span style="color:#d19a66;">false</span><span>} </span><span style="font-style:italic;color:#848da1;">// catch all for any other response code 780</span><span> ] 781</span></code></pre> 782<p>When htmx receives a response it will iterate in order over the <code>htmx.config.responseHandling</code> array and test if the 783<code>code</code> property of a given object, when treated as a Regular Expression, matches the current response. If an entry 784does match the current response code, it will be used to determine if and how the response will be processed.</p> 785<p>The fields available for response handling configuration on entries in this array are:</p> 786<ul> 787<li><code>code</code> - a String representing a regular expression that will be tested against response codes.</li> 788<li><code>swap</code> - <code>true</code> if the response should be swapped into the DOM, <code>false</code> otherwise</li> 789<li><code>error</code> - <code>true</code> if htmx should treat this response as an error</li> 790<li><code>ignoreTitle</code> - <code>true</code> if htmx should ignore title tags in the response</li> 791<li><code>select</code> - A CSS selector to use to select content from the response</li> 792<li><code>target</code> - A CSS selector specifying an alternative target for the response</li> 793<li><code>swapOverride</code> - An alternative swap mechanism for the response</li> 794</ul> 795<h4 id="response-handling-examples"><a class="zola-anchor" href="#response-handling-examples" aria-label="Anchor link for: response-handling-examples">Configuring Response Handling Examples</a></h4> 796<p>As an example of how to use this configuration, consider a situation when a server-side framework responds with a 797<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422"><code>422 - Unprocessable Entity</code></a> response when validation errors occur. By default, htmx will ignore the response, 798since it matches the Regular Expression <code>[45]..</code>.</p> 799<p>Using the <a href="https://htmx.org/docs/#configuration-options">meta config</a> mechanism for configuring responseHandling, we could add the following 800config:</p> 801<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span style="font-style:italic;color:#848da1;"><!-- 802</span><span style="font-style:italic;color:#848da1;"> * 204 No Content by default does nothing, but is not an error 803</span><span style="font-style:italic;color:#848da1;"> * 2xx, 3xx and 422 responses are non-errors and are swapped 804</span><span style="font-style:italic;color:#848da1;"> * 4xx & 5xx responses are not swapped and are errors 805</span><span style="font-style:italic;color:#848da1;"> * all other responses are swapped using "..." as a catch-all 806</span><span style="font-style:italic;color:#848da1;">--> 807</span><span><</span><span style="color:#e06c75;">meta 808</span><span>
808 </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"htmx-config" 809</span><span> </span><span style="color:#d19a66;">content</span><span>=</span><span style="color:#98c379;">'{ 810</span><span style="color:#98c379;"> "responseHandling":[ 811</span><span style="color:#98c379;"> {"code":"204", "swap": false}, 812</span><span style="color:#98c379;"> {"code":"[23]..", "swap": true}, 813</span><span style="color:#98c379;"> {"code":"422", "swap": true}, 814</span><span style="color:#98c379;"> {"code":"[45]..", "swap": false, "error":true}, 815</span><span style="color:#98c379;"> {"code":"...", "swap": true} 816</span><span style="color:#98c379;"> ] 817</span><span style="color:#98c379;"> }' 818</span><span>/> 819</span></code></pre> 820<p>If you wanted to swap everything, regardless of HTTP response code, you could use this configuration:</p> 821<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">meta </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"htmx-config" </span><span style="color:#d19a66;">content</span><span>=</span><span style="color:#98c379;">'{"responseHandling": [{"code":".*", "swap": true}]}' </span><span>/> </span><span style="font-style:italic;color:#848da1;"><!--all responses are swapped--> 822</span></code></pre> 823<p>Finally, it is worth considering using the <a href="/extensions/response-targets">Response Targets</a> 824extension, which allows you to configure the behavior of response codes declaratively via attributes.</p> 825<h3 id="cors"><a class="zola-anchor" href="#cors" aria-label="Anchor link for: cors">CORS</a></h3> 826<p>When using htmx in a cross origin context, remember to configure your web 827server to set Access-Control headers in order for htmx headers to be visible 828on the client side.</p> 829<ul> 830<li><a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers">Access-Control-Allow-Headers (for request headers)</a></li> 831<li><a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers">Access-Control-Expose-Headers (for response headers)</a></li> 832</ul> 833<p><a href="https://htmx.org/reference/#request_headers">See all the request and response headers that htmx implements.</a></p> 834<h3 id="request-headers"><a class="zola-anchor" href="#request-headers" aria-label="Anchor link for: request-headers">Request Headers</a></h3> 835<p>htmx includes a number of useful headers in requests:</p> 836<table><thead><tr><th>Header</th><th>Description</th></tr></thead><tbody> 837<tr><td><code>HX-Boosted</code></td><td>indicates that the request is via an element using <a href="https://htmx.org/attributes/hx-boost/">hx-boost</a></td></tr> 838<tr><td><code>HX-Current-URL</code></td><td>the current URL of the browser</td></tr> 839<tr><td><code>HX-History-Restore-Request</code></td><td>âtrueâ if the request is for history restoration after a miss in the local history cache</td></tr> 840<tr><td><code>HX-Prompt</code></td><td>the user response to an <a href="https://htmx.org/attributes/hx-prompt/">hx-prompt</a></td></tr> 841<tr><td><code>HX-Request</code></td><td>always âtrueâ except on history restore requests if `htmx.config.historyRestoreAsHxRequestâ disabled</td></tr> 842<tr><td><code>HX-Target</code></td><td>the <code>id</code> of the target element if it exists</td></tr> 843<tr><td><code>HX-Trigger-Name</code></td><td>the <code>name</code> of the triggered element if it exists</td></tr> 844<tr><td><code>HX-Trigger</code></td><td>the <code>id</code> of the triggered element if it exists</td></tr> 845</tbody></table> 846<h3 id="response-headers"><a class="zola-anchor" href="#response-headers" aria-label="Anchor link for: response-headers">Response Headers</a></h3> 847<p>htmx supports some htmx-specific response headers:</p> 848<ul> 849<li><a href="https://htmx.org/headers/hx-location/"><code>HX-Location</code></a> - allows you to do a client-side redirect that does not do a full page reload</li> 850<li><a href="https://htmx.org/headers/hx-push-url/"><code>HX-Push-Url</code></a> - pushes a new url into the history stack</li> 851<li><a href="https://htmx.org/headers/hx-redirect/"><code>HX-Redirect</code></a> - can be used to do a client-side redirect to a new location</li> 852<li><code>HX-Refresh</code> - if set to âtrueâ the client-side will do a full refresh of the page</li> 853<li><a href="https://htmx.org/headers/hx-replace-url/"><code>HX-Replace-Url</code></a> - replaces the current URL in the location bar</li> 854<li><code>HX-Reswap</code> - allows you to specify how the response will be swapped. See <a href="https://htmx.org/attributes/hx-swap/">hx-swap</a> for possible values</li> 855<li><code>HX-Retarget</code>
855 - a CSS selector that updates the target of the content update to a different element on the page</li> 856<li><code>HX-Reselect</code> - a CSS selector that allows you to choose which part of the response is used to be swapped in. Overrides an existing <a href="https://htmx.org/attributes/hx-select/"><code>hx-select</code></a> on the triggering element</li> 857<li><a href="https://htmx.org/headers/hx-trigger/"><code>HX-Trigger</code></a> - allows you to trigger client-side events</li> 858<li><a href="https://htmx.org/headers/hx-trigger/"><code>HX-Trigger-After-Settle</code></a> - allows you to trigger client-side events after the settle step</li> 859<li><a href="https://htmx.org/headers/hx-trigger/"><code>HX-Trigger-After-Swap</code></a> - allows you to trigger client-side events after the swap step</li> 860</ul> 861<p>For more on the <code>HX-Trigger</code> headers, see <a href="https://htmx.org/headers/hx-trigger/"><code>HX-Trigger</code> Response Headers</a>.</p> 862<p>Submitting a form via htmx has the benefit of no longer needing the <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Post/Redirect/Get">Post/Redirect/Get Pattern</a>. 863After successfully processing a POST request on the server, you donât need to return a <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/HTTP_302">HTTP 302 (Redirect)</a>. You can directly return the new HTML fragment.</p> 864<p>Also the response headers above are not provided to htmx for processing with 3xx Redirect response codes like <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/HTTP_302">HTTP 302 (Redirect)</a>. Instead, the browser will intercept the redirection internally and return the headers and response from the redirected URL. Where possible use alternative response codes like 200 to allow returning of these response headers.</p> 865<h3 id="request-operations"><a class="zola-anchor" href="#request-operations" aria-label="Anchor link for: request-operations">Request Order of Operations</a></h3> 866<p>The order of operations in a htmx request are:</p> 867<ul> 868<li>The element is triggered and begins a request 869<ul> 870<li>Values are gathered for the request</li> 871<li>The <code>htmx-request</code> class is applied to the appropriate elements</li> 872<li>The request is then issued asynchronously via AJAX 873<ul> 874<li>Upon getting a response the target element is marked with the <code>htmx-swapping</code> class</li> 875<li>An optional swap delay is applied (see the <a href="https://htmx.org/attributes/hx-swap/">hx-swap</a> attribute)</li> 876<li>The actual content swap is done 877<ul> 878<li>the <code>htmx-swapping</code> class is removed from the target</li> 879<li>the <code>htmx-added</code> class is added to each new piece of content</li> 880<li>the <code>htmx-settling</code> class is applied to the target</li> 881<li>A settle delay is done (default: 20ms)</li> 882<li>The DOM is settled</li> 883<li>the <code>htmx-settling</code> class is removed from the target</li> 884<li>the <code>htmx-added</code> class is removed from each new piece of content</li> 885</ul> 886</li> 887</ul> 888</li> 889</ul> 890</li> 891</ul> 892<p>You can use the <code>htmx-swapping</code> and <code>htmx-settling</code> classes to create 893<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions">CSS transitions</a> between pages.</p> 894<h2 id="validation"><a class="zola-anchor" href="#validation" aria-label="Anchor link for: validation">Validation</a></h2> 895<p>Htmx integrates with the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation">HTML5 Validation API</a> 896and will not issue a request for a form if a validatable input is invalid. This is true for both AJAX requests as well as 897WebSocket sends.</p> 898<p>Htmx fires events around validation that can be used to hook in custom validation and error handling:</p> 899<ul> 900<li><code>htmx:validation:validate</code> - called before an elementâs <code>checkValidity()</code> method is called. May be used to add in 901custom validation logic</li> 902<li><code>htmx:validation:failed</code> - called when <code>checkValidity()</code>
902 returns false, indicating an invalid input</li> 903<li><code>htmx:validation:halted</code> - called when a request is not issued due to validation errors. Specific errors may be found 904in the <code>event.detail.errors</code> object</li> 905</ul> 906<p>Non-form elements do not validate before they make requests by default, but you can enable validation by setting 907the <a href="https://htmx.org/attributes/hx-validate/"><code>hx-validate</code></a> attribute to âtrueâ.</p> 908<p>Normal browser form submission alerts the user of any validation errors automatically and auto focuses on the first invalid input. For backwards compatibility reasons htmx does not report the validation to the users by default and you should always enable this option by setting <code>htmx.config.reportValidityOfForms</code> to <code>true</code> to restore the default browser behavior.</p> 909<h3 id="validation-example"><a class="zola-anchor" href="#validation-example" aria-label="Anchor link for: validation-example">Validation Example</a></h3> 910<p>Here is an example of an input that uses the <a href="/attributes/hx-on"><code>hx-on</code></a> attribute to catch the 911<code>htmx:validation:validate</code> event and require that the input have the value <code>foo</code>:</p> 912<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"example-form" </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/test"</span><span>> 913</span><span> <</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"example" 914</span><span> </span><span style="color:#d19a66;">onkeyup</span><span>=</span><span style="color:#98c379;">"</span><span style="color:#e06c75;">this</span><span>.</span><span style="color:#e06c75;">setCustomValidity</span><span>(</span><span style="color:#98c379;">''</span><span>) </span><span style="font-style:italic;color:#848da1;">// reset the validation on keyup</span><span style="color:#98c379;">" 915</span><span> </span><span style="color:#d19a66;">hx-on:htmx:validation:validate</span><span>=</span><span style="color:#98c379;">"if(this.value != 'foo') { 916</span><span style="color:#98c379;"> this.setCustomValidity('Please enter the value foo') // set the validation error 917</span><span style="color:#98c379;"> htmx.find('#example-form').reportValidity() // report the issue 918</span><span style="color:#98c379;"> }"</span><span>> 919</span><span></</span><span style="color:#e06c75;">form</span><span>> 920</span></code></pre> 921<p>Note that all client side validations must be re-done on the server side, as they can always be bypassed.</p> 922<h2 id="animations"><a class="zola-anchor" href="#animations" aria-label="Anchor link for: animations">Animations</a></h2> 923<p>Htmx allows you to use <a href="https://htmx.org/docs/#css_transitions">CSS transitions</a> 924in many situations using only HTML and CSS.</p> 925<p>Please see the <a href="https://htmx.org/examples/animations/">Animation Guide</a> for more details on the options available.</p> 926<h2 id="extensions"><a class="zola-anchor" href="#extensions" aria-label="Anchor link for: extensions">Extensions</a></h2> 927<p>htmx provides an <a href="/extensions">extensions</a> mechanism that allows you to customize the librariesâ behavior. 928Extensions <a href="/extensions/building">are defined in javascript</a> and then enabled via 929the <a href="https://htmx.org/attributes/hx-ext/"><code>hx-ext</code></a> attribute.</p> 930<h3 id="core-extensions"><a class="zola-anchor" href="#core-extensions" aria-label="Anchor link for: core-extensions">Core Extensions</a></h3> 931<p>htmx supports a few âcoreâ extensions, which are supported by the htmx development team:</p> 932<ul> 933<li><a href="/extensions/head-support">head-support</a> - support for merging head tag information (styles, etc.) in htmx requests</li> 934<li><a href="/extensions/htmx-1-compat">htmx-1-compat</a> - restores htmx 1 defaults & functionality</li> 935<li><a href="/extensions/idiomorph">idiomorph</a> - supports the <code>morph</code> swap strategy using idiomorph</li> 936<li><a href="/extensions/preload">preload</a> - allows you to preload content for better performance</li> 937<li><a href="/extensions/response-targets">response-targets</a> - allows you to target elements based on HTTP response codes (e.g. <code>404</code>)</li> 938<li><a href="/extensions/sse">sse</a> - support for <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events">Server Sent Events</a></li> 939<li><a href="/extensions/ws">ws</a> - support for <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications">Web Sockets</a></li> 940</ul> 941<p>You can see all available extensions on the <a href="/extensions">Extensions</a> page.</p> 942<h3 id="installing-extensions"><a class="zola-anchor" href="#installing-extensions" aria-label="Anchor link for: installing-extensions">Installing Extensions</a></h3> 943<p>The fastest way to install htmx extensions created by others is to load them via a CDN. Remember to always include the core htmx library before the extensions and <a href="https://htmx.org/docs/#enabling-extensions">enable the extension</a>. For example, if you would like to use the <a href="/extensions/response-targets">response-targets</a> extension, you can add this to your head tag:</p> 944<pre data-lang="HTML" style="background-color:#1f2329;color:#abb2bf;" class="language-HTML "><code class="language-HTML" data-lang="HTML"><span><</span><span style="color:#e06c75;">head</span><span>> 945</span><span> <</span><span style="color:#e06c75;">script </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"https://cdn.jsdelivr.net/npm/[email protected]/dist/htmx.min.js" </span><span style="color:#d19a66;">integrity</span><span>=</span><span style="color:#98c379;">"sha384-2OatzQy1H+Zd/IIrjr1TcuDGqLXeHhbooAyJY1KdQMKnr4LZ22k31GBLdYKHmVjg" </span><span style="color:#d19a66;">crossorigin</span><span>=</span><span style="color:#98c379;">"anonymous"</span><span>></</span><span style="color:#e06c75;">script</span><span>> 946</span><span> <</span><span style="color:#e06c75;">script </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"https://cdn.jsdelivr.net/npm/[email protected]" </span><span style="color:#d19a66;">integrity</span><span>=</span><span style="color:#98c379;">"sha384-T41oglUPvXLGBVyRdZsVRxNWnOOqCynaPubjUVjxhsjFTKrFJGEMm3/0KGmNQ+Pg" </span><span style="color:#d19a66;">crossorigin</span><span>=</span><span style="color:#98c379;">"anonymous"</span><span>></</span><span style="color:#e06c75;">script</span><span>> 947</span><span></</span><span style="color:#e06c75;">head</span><span>> 948</span><span><</span><span style="color:#e06c75;">body </span><span style="color:#d19a66;">hx-ext</span><span>=</span><span style="color:#98c379;">"extension-name"</span><span>> 949</span><span> ... 950</span></code></pre> 951<p>An unminified version is also available at <code>https://cdn.jsdelivr.net/npm/htmx-ext-extension-name/dist/extension-name.js</code> (replace <code>extension-name</code> with the name of the extension).</p> 952<p>While the CDN approach is simple, you may want to consider <a rel="noopener" target="_blank" href="https://blog.wesleyac.com/posts/why-not-javascript-cdn">not using CDNs in production</a>. The next easiest way to install htmx extensions is to simply copy them into your project. Download the extension from <code>https://cdn.jsdelivr.net/npm/htmx-ext-extension-name</code> (replace <code>extension-name</code> with the name of the extension) e.g., https://cdn.jsdelivr.net/npm/htmx-ext-response-targets. Then add it to the appropriate directory in your project and include it where necessary with a <code><script></code> tag.</p> 953<p>
953For npm-style build systems, you can install htmx extensions via <a rel="noopener" target="_blank" href="https://www.npmjs.com/">npm</a> (replace <code>extension-name</code> with the name of the extension):</p> 954<pre data-lang="sh" style="background-color:#1f2329;color:#abb2bf;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#e06c75;">npm</span><span> install htmx-ext-extension-name 955</span></code></pre> 956<p>After installing, youâll need to use appropriate tooling to bundle <code>node_modules/htmx-ext-extension-name/dist/extension-name.js</code> (or <code>.min.js</code>). For example, you might bundle the extension with htmx core from <code>node_modules/htmx.org/dist/htmx.js</code> and project-specific code.</p> 957<p>If you are using a bundler to manage your javascript (e.g. Webpack, Rollup):</p> 958<ul> 959<li>Install <code>htmx.org</code> and <code>htmx-ext-extension-name</code> via npm (replace <code>extension-name</code> with the name of the extension)</li> 960<li>Import both packages to your <code>index.js</code></li> 961</ul> 962<pre data-lang="JS" style="background-color:#1f2329;color:#abb2bf;" class="language-JS "><code class="language-JS" data-lang="JS"><span style="color:#c678dd;">import </span><span style="color:#98c379;">`htmx.org`</span><span>; 963</span><span style="color:#c678dd;">import </span><span style="color:#98c379;">`htmx-ext-extension-name`</span><span>; </span><span style="font-style:italic;color:#848da1;">// replace `extension-name` with the name of the extension 964</span></code></pre> 965<p>Note: <a href="/extensions/idiomorph">Idiomorph</a> does not follow the naming convention of htmx extensions. Use <code>idiomorph</code> instead of <code>htmx-ext-idiomorph</code>. For example, <code>https://cdn.jsdelivr.net/npm/idiomorph</code> or <code>npm install idiomorph</code>.</p> 966<p>Note: Community extensions hosted outside this repository might have different installation instructions. Please check the corresponding repository for set-up guidance.</p> 967<h3 id="enabling-extensions"><a class="zola-anchor" href="#enabling-extensions" aria-label="Anchor link for: enabling-extensions">Enabling Extensions</a></h3> 968<p>To enable an extension, add a <code>hx-ext="extension-name"</code> attribute to <code><body></code> or another HTML element (replace <code>extension-name</code> with the name of the extension). The extension will be applied to all child elements.</p> 969<p>The following example shows how to enable <a href="/extensions/response-targets">response-targets</a> extension, allowing you to specify different target elements to be swapped based on HTTP response code.</p> 970<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">body </span><span style="color:#d19a66;">hx-ext</span><span>=</span><span style="color:#98c379;">"response-targets"</span><span>> 971</span><span> ... 972</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/register" </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#response-div" </span><span style="color:#d19a66;">hx-target-404</span><span>=</span><span style="color:#98c379;">"#not-found"</span><span>> 973</span><span> Register! 974</span><span> </</span><span style="color:#e06c75;">button</span><span>> 975</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"response-div"</span><span>></</span><span style="color:#e06c75;">div</span><span>> 976</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"not-found"</span><span>></</span><span style="color:#e06c75;">div</span><span>> 977</span><span> ... 978</span><span></</span><span style="color:#e06c75;">body</span><span>> 979</span></code></pre> 980<h3 id="creating-extensions"><a class="zola-anchor" href="#creating-extensions" aria-label="Anchor link for: creating-extensions">Creating Extensions</a></h3> 981<p>If you are interested in adding your own extension to htmx, please <a href="/extensions/building">see the extension docs</a>.</p> 982<h2 id="events"><a class="zola-anchor" href="#events" aria-label="Anchor link for: events">Events & Logging</a></h2> 983<p>Htmx has an extensive <a href="https://htmx.org/reference/#events">events mechanism</a>, which doubles as the logging system.</p> 984<p>If you want to register for a given htmx event you can use</p> 985<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span>document.body.</span><span style="color:#56b6c2;">addEventListener</span><span>(</span><span style="color:#98c379;">'htmx:load'</span><span>, </span><span style="color:#c678dd;">function</span><span>(</span><span style="color:#e06c75;">evt</span><span>) { 986</span><span> </span><span style="color:#e06c75;">myJavascriptLib</span><span>.</span><span style="color:#61afef;">init</span><span>(</span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">elt</span><span>); 987</span><span>}); 988</span></code></pre> 989<p>or, if you would prefer, you can use the following htmx helper:</p> 990<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#61afef;">on</span><span>(</span><span style="color:#98c379;">"htmx:load"</span><span>, </span><span style="color:#c678dd;">function</span><span>(</span><span style="color:#e06c75;">evt</span><span>) { 991</span><span> </span><span style="color:#e06c75;">myJavascriptLib</span><span>.</span><span style="color:#61afef;">init</span><span>(</span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">elt</span><span>); 992</span><span>}); 993</span></code></pre> 994<p>The <code>htmx:load</code> event is fired every time an element is loaded into the DOM by htmx, and is effectively the equivalent 995to the normal <code>load</code> event.</p> 996<p>Some common uses for htmx events are:</p> 997<h3 id="init_3rd_party_with_events"><a class="zola-anchor" href="#init_3rd_party_with_events" aria-label="Anchor link for: init_3rd_party_with_events">Initialize A 3rd Party Library With Events</a></h3> 998<p>Using the <code>htmx:load</code> event to initialize content is so common that htmx provides a helper function:</p> 999<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#56b6c2;">onLoad</span><span>(</span><span style="color:#c678dd;">function</span><span>(</span><span style="color:#e06c75;">target</span><span>) { 1000</span><span> </span><span style="color:#e06c75;">myJavascriptLib</span><span>.</span><span style="color:#61afef;">init</span><span>(</span><span style="color:#e06c75;">target</span><span>); 1001</span><span>}); 1002</span></code></pre> 1003<p>This does the same thing as the first example, but is a little cleaner.</p> 1004<h3 id="config_request_with_events"><a class="zola-anchor" href="#config_request_with_events" aria-label="Anchor link for: config_request_with_events">Configure a Request With Events</a></h3> 1005<p>You can handle the <a href="https://htmx.org/events/#htmx:configRequest"><code>htmx:configRequest</code></a> event in order to modify an AJAX request before it is issued:</p> 1006<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span>document.body.</span><span style="color:#56b6c2;">addEventListener</span><span>(</span><span style="color:#98c379;">'htmx:configRequest'</span><span>, </span><span style="color:#c678dd;">function</span><span>(</span><span style="color:#e06c75;">evt</span><span>) { 1007</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">parameters</span><span>
1007[</span><span style="color:#98c379;">'auth_token'</span><span>] = </span><span style="color:#61afef;">getAuthToken</span><span>(); </span><span style="font-style:italic;color:#848da1;">// add a new parameter into the request 1008</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.headers[</span><span style="color:#98c379;">'Authentication-Token'</span><span>] = </span><span style="color:#61afef;">getAuthToken</span><span>(); </span><span style="font-style:italic;color:#848da1;">// add a new header into the request 1009</span><span>}); 1010</span></code></pre> 1011<p>Here we add a parameter and header to the request before it is sent.</p> 1012<h3 id="modifying_swapping_behavior_with_events"><a class="zola-anchor" href="#modifying_swapping_behavior_with_events" aria-label="Anchor link for: modifying_swapping_behavior_with_events">Modifying Swapping Behavior With Events</a></h3> 1013<p>You can handle the <a href="https://htmx.org/events/#htmx:beforeSwap"><code>htmx:beforeSwap</code></a> event in order to modify the swap behavior of htmx:</p> 1014<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span>document.body.</span><span style="color:#56b6c2;">addEventListener</span><span>(</span><span style="color:#98c379;">'htmx:beforeSwap'</span><span>, </span><span style="color:#c678dd;">function</span><span>(</span><span style="color:#e06c75;">evt</span><span>) { 1015</span><span> </span><span style="color:#c678dd;">if</span><span>(</span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">xhr</span><span>.status === </span><span style="color:#d19a66;">404</span><span>){ 1016</span><span> </span><span style="font-style:italic;color:#848da1;">// alert the user when a 404 occurs (maybe use a nicer mechanism than alert()) 1017</span><span> </span><span style="color:#61afef;">alert</span><span>(</span><span style="color:#98c379;">"Error: Could Not Find Resource"</span><span>); 1018</span><span> } </span><span style="color:#c678dd;">else if</span><span>(</span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">xhr</span><span>.status === </span><span style="color:#d19a66;">422</span><span>){ 1019</span><span> </span><span style="font-style:italic;color:#848da1;">// allow 422 responses to swap as we are using this as a signal that 1020</span><span> </span><span style="font-style:italic;color:#848da1;">// a form was submitted with bad data and want to rerender with the 1021</span><span> </span><span style="font-style:italic;color:#848da1;">// errors 1022</span><span> </span><span style="font-style:italic;color:#848da1;">// 1023</span><span> </span><span style="font-style:italic;color:#848da1;">// set isError to false to avoid error logging in console 1024</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">shouldSwap </span><span>= </span><span style="color:#d19a66;">true</span><span>; 1025</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">isError </span><span>= </span><span style="color:#d19a66;">false</span><span>; 1026</span><span> } </span><span style="color:#c678dd;">else if</span><span>(</span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">xhr</span><span>.status === </span><span style="color:#d19a66;">418</span><span>){ 1027</span><span> </span><span style="font-style:italic;color:#848da1;">// if the response code 418 (I'm a teapot) is returned, retarget the 1028</span><span> </span><span style="font-style:italic;color:#848da1;">// content of the response to the element with the id `teapot` 1029</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">shouldSwap </span><span>= </span><span style="color:#d19a66;">true</span><span>; 1030</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.target = </span><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#56b6c2;">find</span><span>(</span><span style="color:#98c379;">"#teapot"</span><span>); 1031</span><span> } 1032</span><span>}); 1033</span></code></pre> 1034<p>Here we handle a few <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses">400-level error response codes</a> 1035that would normally not do a swap in htmx.</p> 1036<h3 id="event_naming"><a class="zola-anchor" href="#event_naming" aria-label="Anchor link for: event_naming">Event Naming</a></h3> 1037<p>Note that all events are fired with two different names</p> 1038<ul> 1039<li>Camel Case</li> 1040<li>Kebab Case</li> 1041</ul> 1042<p>So, for example, you can listen for <code>htmx:afterSwap</code> or for <code>htmx:after-swap</code>. This facilitates interoperability 1043with other libraries. <a rel="noopener" target="_blank" href="https://github.com/alpinejs/alpine/">Alpine.js</a>, for example, requires kebab case.</p> 1044<h3 id="logging"><a class="zola-anchor" href="#logging" aria-label="Anchor link for: logging">Logging</a></h3> 1045<p>If you set a logger at <code>htmx.logger</code>, every event will be logged. This can be very useful for troubleshooting:</p> 1046<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#61afef;">logger </span><span>= </span><span style="color:#c678dd;">function</span><span>(</span><span style="color:#e06c75;">elt</span><span>, </span><span style="color:#e06c75;">event</span><span>, </span><span style="color:#e06c75;">data</span><span>) { 1047</span><span> </span><span style="color:#c678dd;">if</span><span>(</span><span style="color:#e5c07b;">console</span><span>) { 1048</span><span> </span><span style="color:#e5c07b;">console</span><span>.</span><span style="color:#56b6c2;">log</span><span>(event, </span><span style="color:#e06c75;">elt</span><span>, </span><span style="color:#e06c75;">data</span><span>); 1049</span><span> } 1050</span><span>} 1051</span></code></pre> 1052<h2 id="debugging"><a class="zola-anchor" href="#debugging" aria-label="Anchor link for: debugging">Debugging</a></h2> 1053<p>Declarative and event driven programming with htmx (or any other declarative language) can be a wonderful and highly productive 1054activity, but one disadvantage when compared with imperative approaches is that it can be trickier to debug.</p> 1055<p>Figuring out why something <em>isnât</em> happening, for example, can be difficult if you donât know the tricks.</p> 1056<p>Well, here are the tricks:</p> 1057<p>The first debugging tool you can use is the <code>htmx.logAll()</code> method. This will log every event that htmx triggers and 1058will allow you to see exactly what the library is doing.</p> 1059<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#61afef;">logAll</span><span>(); 1060</span></code></pre> 1061<p>Of course, that wonât tell you why htmx <em>isnât</em> doing something. You might also not know <em>what</em> events a DOM 1062element is firing to use as a trigger. To address this, you can use the 1063<a rel="noopener" target="_blank" href="https://developers.google.com/web/updates/2015/05/quickly-monitor-events-from-the-console-panel"><code>monitorEvents()</code></a> method available in the 1064browser console:</p> 1065<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#61afef;">monitorEvents</span><span>(</span><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#56b6c2;">find</span><span>(</span><span style="color:#98c379;">"#theElement"</span><span>)); 1066</span></code></pre> 1067<p>This will spit out all events that are occurring on the element with the id <code>theElement</code> to the console, and allow you 1068to see exactly what is going on with it.</p> 1069<p>Note that this <em>only</em> works from the console, you cannot embed it in a script tag on your page.</p> 1070<p>Finally, push come shove, you might want to just debug <code>htmx.js</code> by loading up the unminimized version. Itâs 1071about 2500 lines of javascript, so not an insurmountable amount of code. You would most likely want to set a break 1072point in the <code>issueAjaxRequest()</code> and <code>handleAjaxResponse()</code> methods to see whatâs going on.</p> 1073<p>And always feel free to jump on the <a rel="noopener" target="_blank" href="https://htmx.org/discord">Discord</a> if you need help.</p> 1074<h3 id="creating-demos"><a class="zola-anchor" href="#creating-demos" aria-label="Anchor link for: creating-demos">Creating Demos</a></h3> 1075<p>Sometimes, in order to demonstrate a bug or clarify a usage, it is nice to be able to use a javascript snippet 1076site like <a rel="noopener" target="_blank" href="https://jsfiddle.net/">jsfiddle</a>. To facilitate easy demo creation, htmx hosts a demo script 1077site that will install:</p> 1078<ul> 1079<li>htmx</li> 1080<li>hyperscript</li> 1081<li>a request mocking library</li> 1082</ul> 1083<p>Simply add the following script tag to your demo/fiddle/whatever:</p> 1084<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">script </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"https://demo.htmx.org"</span><span>></</span><span style="color:#e06c75;">script</span><span>> 1085</span></code></pre> 1086<p>This helper allows you to add mock responses by adding <code>template</code> tags with a <code>url</code> attribute to indicate which URL. 1087The response for that url will be the innerHTML of the template, making it easy to construct mock responses. You can 1088add a delay to the response with a <code>delay</code> attribute, which should be an integer indicating the number of milliseconds 1089to delay</p> 1090<p>You may embed simple expressions in the template with the <code>${}</code> syntax.</p> 1091<p>Note that this should only be used for demos and is in no way guaranteed to work for long periods of time 1092as it will always be grabbing the latest versions htmx and hyperscript!</p> 1093<h4 id="demo-example"><a class="zola-anchor" href="#demo-example" aria-label="Anchor link for: demo-example">Demo Example</a></h4> 1094<p>Here is an example of the code in action:</p> 1095<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span style="font-style:italic;color:#848da1;"><!-- load demo environment --> 1096</span><span><</span><span style="color:#e06c75;">script </span><span style="color:#d19a66;">src</span><span>=</span><span style="color:#98c379;">"https://demo.htmx.org"</span><span>></</span><span style="color:#e06c75;">script</span><span>> 1097</span><span> 1098</span><span style="font-style:italic;color:#848da1;"><!-- post to /foo --> 1099</span><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/foo" </span><span style="color:#d19a66;">hx-target</span><span>=</span><span style="color:#98c379;">"#result"</span><span>> 1100</span><span> Count Up 1101</span><span></</span><span style="color:#e06c75;">button</span><span>> 1102</span><span><</span><span style="color:#e06c75;">output </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"result"</span><span>></</span><span style="color:#e06c75;">output</span><span>> 1103</span><span> 1104</span><span style="font-style:italic;color:#848da1;"><!-- respond to /foo with some dynamic content in a template tag --> 1105</span><span><</span><span style="color:#e06c75;">script</span><span>> 1106</span><span> </span><span style="color:#e06c75;">globalInt </span><span>= </span><span style="color:#d19a66;">0</span><span>; 1107</span><span></</span><span style="color:#e06c75;">script</span><span>> 1108</span><span><</span><span style="color:#e06c75;">template </span><span style="color:#d19a66;">url</span><span>=</span><span style="color:#98c379;">"/foo" </span><span style="color:#d19a66;">delay</span><span>=</span><span style="color:#98c379;">"500"</span><span>> </span><span style="font-style:italic;color:#848da1;"><!-- note the url and delay attributes --> 1109</span><span> ${globalInt++} 1110</span><span></</span><span style="color:#e06c75;">template</span><span>> 1111</span><span> 1112</span></code></pre> 1113<h2 id="scripting"><a class="zola-anchor" href="#scripting" aria-label="Anchor link for: scripting">Scripting</a></h2> 1114<p>While htmx encourages a hypermedia approach to building web applications, it offers many options for client scripting. Scripting is included in the REST-ful description of web architecture, see: <a rel="noopener" target="_blank" href="https://roy.gbiv.com/pubs/dissertation/rest_arch_style.htm#sec_5_1_7">Code-On-Demand</a>. As much as is feasible, we recommend a <a href="/essays/hypermedia-friendly-scripting">hypermedia-friendly</a>
1114 approach to scripting in your web application:</p> 1115<ul> 1116<li><a href="/essays/hypermedia-friendly-scripting#prime_directive">Respect HATEOAS</a></li> 1117<li><a href="/essays/hypermedia-friendly-scripting#events">Use events to communicate between components</a></li> 1118<li><a href="/essays/hypermedia-friendly-scripting#islands">Use islands to isolate non-hypermedia components from the rest of your application</a></li> 1119<li><a href="/essays/hypermedia-friendly-scripting#inline">Consider inline scripting</a></li> 1120</ul> 1121<p>The primary integration point between htmx and scripting solutions is the <a href="https://htmx.org/docs/#events">events</a> that htmx sends and can 1122respond to. See the SortableJS example in the <a href="https://htmx.org/docs/#3rd-party">3rd Party Javascript</a> section for a good template for 1123integrating a JavaScript library with htmx via events.</p> 1124<p>Scripting solutions that pair well with htmx include:</p> 1125<ul> 1126<li><a rel="noopener" target="_blank" href="http://vanilla-js.com/">VanillaJS</a> - Simply using the built-in abilities of JavaScript to hook in event handlers to 1127respond to the events htmx emits can work very well for scripting. This is an extremely lightweight and increasingly 1128popular approach.</li> 1129<li><a rel="noopener" target="_blank" href="https://alpinejs.dev/">AlpineJS</a> - Alpine.js provides a rich set of tools for creating sophisticated front end scripts, 1130including reactive programming support, while still remaining extremely lightweight. Alpine encourages the âinline scriptingâ 1131approach that we feel pairs well with htmx.</li> 1132<li><a rel="noopener" target="_blank" href="https://jquery.com/">jQuery</a> - Despite its age and reputation in some circles, jQuery pairs very well with htmx, particularly 1133in older code-bases that already have a lot of jQuery in them.</li> 1134<li><a rel="noopener" target="_blank" href="https://hyperscript.org">hyperscript</a> - Hyperscript is an experimental front-end scripting language created by the same 1135team that created htmx. It is designed to embed well in HTML and both respond to and create events, and pairs very well 1136with htmx.</li> 1137</ul> 1138<p>We have an entire chapter entitled <a rel="noopener" target="_blank" href="https://hypermedia.systems/client-side-scripting/">âClient-Side Scriptingâ</a> in <a rel="noopener" target="_blank" href="https://hypermedia.systems">our 1139book</a> that looks at how scripting can be integrated into your htmx-based application.</p> 1140<h3 id="the-hx-on-attributes"><a class="zola-anchor" href="#the-hx-on-attributes" aria-label="Anchor link for: the-hx-on-attributes"><a name="hx-on"></a><a href="https://htmx.org/docs/#hx-on">The <code>hx-on*</code> Attributes</a></a></h3> 1141<p>HTML allows the embedding of inline scripts via the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Events/Event_handlers#using_onevent_properties"><code>onevent</code> properties</a>, 1142such as <code>onClick</code>:</p> 1143<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">onclick</span><span>=</span><span style="color:#98c379;">"</span><span style="color:#e06c75;">alert</span><span>(</span><span style="color:#98c379;">'You clicked me!'</span><span>)</span><span style="color:#98c379;">"</span><span>> 1144</span><span> Click Me! 1145</span><span></</span><span style="color:#e06c75;">button</span><span>> 1146</span></code></pre> 1147<p>This feature allows scripting logic to be co-located with the HTML elements the logic applies to, giving good 1148<a href="/essays/locality-of-behaviour">Locality of Behaviour (LoB)</a>. Unfortunately, HTML only allows <code>on*</code> attributes for a fixed 1149number of <a rel="noopener" target="_blank" href="https://www.w3schools.com/tags/ref_eventattributes.asp">specific DOM events</a> (e.g. <code>onclick</code>) and 1150doesnât provide a generalized mechanism for responding to arbitrary events on elements.</p> 1151<p>In order to address this shortcoming, htmx offers <a href="/attributes/hx-on"><code>hx-on*</code></a> attributes. These attributes allow 1152you to respond to any event in a manner that preserves the LoB of the standard <code>on*</code> properties.</p> 1153<p>If we wanted to respond to the <code>click</code> event using an <code>hx-on</code> attribute, we would write this:</p> 1154<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-on:click</span><span>=</span><span style="color:#98c379;">"alert('You clicked me!')"</span><span>> 1155</span><span> Click Me! 1156</span><span></</span><span style="color:#e06c75;">button</span><span>> 1157</span></code></pre> 1158<p>So, the string <code>hx-on</code>, followed by a colon (or a dash), then by the name of the event.</p> 1159<p>For a <code>click</code> event, of course, we would recommend sticking with the standard <code>onclick</code> attribute. However, consider an 1160htmx-powered button that wishes to add a parameter to a request using the <code>htmx:config-request</code> event. This would not 1161be possible using a standard <code>on*</code> property, but it can be done using the <code>hx-on:htmx:config-request</code> attribute:</p> 1162<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/example" 1163</span><span> </span><span style="color:#d19a66;">hx-on:htmx:config-request</span><span>=</span><span style="color:#98c379;">"event.detail.parameters.example = 'Hello Scripting!'"</span><span>> 1164</span><span> Post Me! 1165</span><span></</span><span style="color:#e06c75;">button</span><span>> 1166</span></code></pre> 1167<p>Here the <code>example</code> parameter is added to the <code>POST</code> request before it is issued, with the value âHello Scripting!â.</p> 1168<p>Another usecase is to <a href="https://htmx.org/examples/reset-user-input/">reset user input</a> on successful requests using the <code>afterRequest</code> 1169event, avoiding the need for something like an out of band swap.</p> 1170<p>The <code>hx-on*</code> attributes are a very simple mechanism for generalized embedded scripting. It is <em>not</em> a replacement for more 1171fully developed front-end scripting solutions such as AlpineJS or hyperscript. It can, however, augment a VanillaJS-based
1172approach to scripting in your htmx-powered application.</p> 1173<p>Note that HTML attributes are <em>case insensitive</em>. This means that, unfortunately, events that rely on capitalization/ 1174camel casing, cannot be responded to. If you need to support camel case events we recommend using a more fully 1175functional scripting solution such as AlpineJS or hyperscript. htmx dispatches all its events in both camelCase and in 1176kebab-case for this very reason.</p> 1177<h3 id="3rd-party"><a class="zola-anchor" href="#3rd-party" aria-label="Anchor link for: 3rd-party">3rd Party Javascript</a></h3> 1178<p>Htmx integrates fairly well with third party libraries. If the library fires events on the DOM, you can use those events to 1179trigger requests from htmx.</p> 1180<p>A good example of this is the <a href="https://htmx.org/examples/sortable/">SortableJS demo</a>:</p> 1181<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">form </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"sortable" </span><span style="color:#d19a66;">hx-post</span><span>=</span><span style="color:#98c379;">"/items" </span><span style="color:#d19a66;">hx-trigger</span><span>=</span><span style="color:#98c379;">"end"</span><span>> 1182</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">class</span><span>=</span><span style="color:#98c379;">"htmx-indicator"</span><span>>Updating...</</span><span style="color:#e06c75;">div</span><span>> 1183</span><span> <</span><span style="color:#e06c75;">div</span><span>><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">'hidden' </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">'item' </span><span style="color:#d19a66;">value</span><span>=</span><span style="color:#98c379;">'1'</span><span>/>Item 1</</span><span style="color:#e06c75;">div</span><span>> 1184</span><span> <</span><span style="color:#e06c75;">div</span><span>><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">'hidden' </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">'item' </span><span style="color:#d19a66;">value</span><span>=</span><span style="color:#98c379;">'2'</span><span>/>Item 2</</span><span style="color:#e06c75;">div</span><span>> 1185</span><span> <</span><span style="color:#e06c75;">div</span><span>><</span><span style="color:#e06c75;">input </span><span style="color:#d19a66;">type</span><span>=</span><span style="color:#98c379;">'hidden' </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">'item' </span><span style="color:#d19a66;">value</span><span>=</span><span style="color:#98c379;">'2'</span><span>/>Item 3</</span><span style="color:#e06c75;">div</span><span>> 1186</span><span></</span><span style="color:#e06c75;">form</span><span>> 1187</span></code></pre> 1188<p>With Sortable, as with most javascript libraries, you need to initialize content at some point.</p> 1189<p>In jquery you might do this like so:</p> 1190<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#61afef;">$</span><span>(document).</span><span style="color:#61afef;">ready</span><span>(</span><span style="color:#c678dd;">function</span><span>() { 1191</span><span> </span><span style="color:#c678dd;">var </span><span style="color:#e06c75;">sortables </span><span>= document.body.</span><span style="color:#56b6c2;">querySelectorAll</span><span>(</span><span style="color:#98c379;">".sortable"</span><span>); 1192</span><span> </span><span style="color:#c678dd;">for </span><span>(</span><span style="color:#c678dd;">var </span><span style="color:#e06c75;">i </span><span>= </span><span style="color:#d19a66;">0</span><span>; </span><span style="color:#e06c75;">i </span><span>< </span><span style="color:#e06c75;">sortables</span><span>.length; </span><span style="color:#e06c75;">i</span><span>++) { 1193</span><span> </span><span style="color:#c678dd;">var </span><span style="color:#e06c75;">sortable </span><span>= </span><span style="color:#e06c75;">sortables</span><span>
1193[</span><span style="color:#e06c75;">i</span><span>]; 1194</span><span> new Sortable(</span><span style="color:#e06c75;">sortable</span><span>, { 1195</span><span> animation: </span><span style="color:#d19a66;">150</span><span>, 1196</span><span> ghostClass: </span><span style="color:#98c379;">'blue-background-class' 1197</span><span> }); 1198</span><span> } 1199</span><span>}); 1200</span></code></pre> 1201<p>In htmx, you would instead use the <code>htmx.onLoad</code> function, and you would select only from the newly loaded content, 1202rather than the entire document:</p> 1203<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#56b6c2;">onLoad</span><span>(</span><span style="color:#c678dd;">function</span><span>(</span><span style="color:#e06c75;">content</span><span>) { 1204</span><span> </span><span style="color:#c678dd;">var </span><span style="color:#e06c75;">sortables </span><span>= </span><span style="color:#e06c75;">content</span><span>.</span><span style="color:#56b6c2;">querySelectorAll</span><span>(</span><span style="color:#98c379;">".sortable"</span><span>); 1205</span><span> </span><span style="color:#c678dd;">for </span><span>(</span><span style="color:#c678dd;">var </span><span style="color:#e06c75;">i </span><span>= </span><span style="color:#d19a66;">0</span><span>; </span><span style="color:#e06c75;">i </span><span>< </span><span style="color:#e06c75;">sortables</span><span>.length; </span><span style="color:#e06c75;">i</span><span>++) { 1206</span><span> </span><span style="color:#c678dd;">var </span><span style="color:#e06c75;">sortable </span><span>= </span><span style="color:#e06c75;">sortables</span><span>[</span><span style="color:#e06c75;">i</span><span>]; 1207</span><span> new Sortable(</span><span style="color:#e06c75;">sortable</span><span>, { 1208</span><span> animation: </span><span style="color:#d19a66;">150</span><span>, 1209</span><span> ghostClass: </span><span style="color:#98c379;">'blue-background-class' 1210</span><span> }); 1211</span><span> } 1212</span><span>}) 1213</span></code></pre> 1214<p>This will ensure that as new content is added to the DOM by htmx, sortable elements are properly initialized.</p> 1215<p>If javascript adds content to the DOM that has htmx attributes on it, you need to make sure that this content 1216is initialized with the <code>htmx.process()</code> function.</p> 1217<p>For example, if you were to fetch some data and put it into a div using the <code>fetch</code> API, and that HTML had 1218htmx attributes in it, you would need to add a call to <code>htmx.process()</code> like this:</p> 1219<pre data-lang="js" style="background-color:#1f2329;color:#abb2bf;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#c678dd;">let </span><span style="color:#e06c75;">myDiv </span><span>= document.</span><span style="color:#56b6c2;">getElementById</span><span>(</span><span style="color:#98c379;">'my-div'</span><span>) 1220</span><span style="color:#61afef;">fetch</span><span>(</span><span style="color:#98c379;">'http://example.com/movies.json'</span><span>) 1221</span><span> .</span><span style="color:#56b6c2;">then</span><span>(</span><span style="color:#e06c75;">response </span><span style="color:#c678dd;">=> </span><span style="color:#e06c75;">response</span><span>.</span><span style="color:#61afef;">text</span><span>()) 1222</span><span> .</span><span style="color:#56b6c2;">then</span><span>(</span><span style="color:#e06c75;">data </span><span style="color:#c678dd;">=> </span><span>{ </span><span style="color:#e06c75;">myDiv</span><span>.</span><span style="color:#e06c75;">innerHTML </span><span>= </span><span style="color:#e06c75;">data</span><span>; </span><span style="color:#e06c75;">htmx</span><span>.</span><span style="color:#61afef;">process</span><span>(</span><span style="color:#e06c75;">myDiv</span><span>); } ); 1223</span></code></pre> 1224<p>Some 3rd party libraries create content from HTML template elements. For instance, Alpine JS uses the <code>x-if</code> 1225attribute on templates to add content conditionally. Such templates are not initially part of the DOM and, 1226if they contain htmx attributes, will need a call to <code>htmx.process()</code> after they are loaded. The following 1227example uses Alpineâs <code>$watch</code> function to look for a change of value that would trigger conditional content:</p> 1228<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">x-data</span><span>=</span><span style="color:#98c379;">"{show_new: false}" 1229</span><span> </span><span style="color:#d19a66;">x-init</span><span>=</span><span style="color:#98c379;">"$watch('show_new', value => { 1230</span><span style="color:#98c379;"> if (show_new) { 1231</span><span style="color:#98c379;"> htmx.process(document.querySelector('#new_content')) 1232</span><span style="color:#98c379;"> } 1233</span><span style="color:#98c379;"> })"</span><span>> 1234</span><span> <</span><span style="color:#e06c75;">button </span><span style="color:#d19a66;">@click </span><span>= </span><span style="color:#98c379;">"show_new = !show_new"</span><span>>Toggle New Content</</span><span style="color:#e06c75;">button</span><span>> 1235</span><span> <</span><span style="color:#e06c75;">template </span><span style="color:#d19a66;">x-if</span><span>=</span><span style="color:#98c379;">"show_new"</span><span>> 1236</span><span> <</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">id</span><span>=</span><span style="color:#98c379;">"new_content"</span><span>> 1237</span><span> <</span><span style="color:#e06c75;">a </span><span style="color:#d19a66;">
1237hx-get</span><span>=</span><span style="color:#98c379;">"/server/newstuff" </span><span style="color:#d19a66;">href</span><span>=</span><span style="color:#98c379;">"#"</span><span>>New Clickable</</span><span style="color:#e06c75;">a</span><span>> 1238</span><span> </</span><span style="color:#e06c75;">div</span><span>> 1239</span><span> </</span><span style="color:#e06c75;">template</span><span>> 1240</span><span></</span><span style="color:#e06c75;">div</span><span>> 1241</span></code></pre> 1242<h4 id="web-components"><a class="zola-anchor" href="#web-components" aria-label="Anchor link for: web-components">Web Components</a></h4> 1243<p>Please see the <a href="https://htmx.org/examples/web-components/">Web Components Examples</a> page for examples on how to integrate htmx 1244with web components.</p> 1245<h2 id="caching"><a class="zola-anchor" href="#caching" aria-label="Anchor link for: caching">Caching</a></h2> 1246<p>htmx works with standard <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching">HTTP caching</a> 1247mechanisms out of the box.</p> 1248<p>If your server adds the 1249<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified"><code>Last-Modified</code></a> 1250HTTP response header to the response for a given URL, the browser will automatically add the 1251<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since"><code>If-Modified-Since</code></a> 1252request HTTP header to the next requests to the same URL. Be mindful that if 1253your server can render different content for the same URL depending on some other 1254headers, you need to use the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#vary"><code>Vary</code></a> 1255response HTTP header. For example, if your server renders the full HTML when the 1256<code>HX-Request</code> header is missing or <code>false</code>, and it renders a fragment of that HTML 1257when <code>HX-Request: true</code>, you need to add <code>Vary: HX-Request</code>. That causes the cache to be 1258keyed based on a composite of the response URL and the <code>HX-Request</code> request header â 1259rather than being based just on the response URL. Always disable <code>htmx.config.historyRestoreAsHxRequest</code> 1260so that these history full HTML requests are not cached with partial fragment responses.</p> 1261<p>If you are unable (or unwilling) to use the <code>Vary</code> header, you can alternatively set the configuration parameter 1262<code>getCacheBusterParam</code> to <code>true</code>. If this configuration variable is set, htmx will include a cache-busting parameter 1263in <code>GET</code> requests that it makes, which will prevent browsers from caching htmx-based and non-htmx based responses 1264in the same cache slot.</p> 1265<p>htmx also works with <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag"><code>ETag</code></a> 1266as expected. Be mindful that if your server can render different content for the same 1267URL (for example, depending on the value of the <code>HX-Request</code> header), the server needs 1268to generate a different <code>ETag</code> for each content.</p> 1269<h2 id="security"><a class="zola-anchor" href="#security" aria-label="Anchor link for: security">Security</a></h2> 1270<p>htmx allows you to define logic directly in your DOM. This has a number of advantages, the largest being 1271<a href="https://htmx.org/essays/locality-of-behaviour/">Locality of Behavior</a>, which makes your system easier to understand and 1272maintain.</p> 1273<p>A concern with this approach, however, is security: since htmx increases the expressiveness of HTML, if a malicious 1274user is able to inject HTML into your application, they can leverage this expressiveness of htmx to malicious 1275ends.</p> 1276<h3 id="rule-1-escape-all-user-content"><a class="zola-anchor" href="#rule-1-escape-all-user-content" aria-label="Anchor link for: rule-1-escape-all-user-content">Rule 1: Escape All User Content</a></h3> 1277<p>The first rule of HTML-based web development has always been: <em>do not trust input from the user</em>. You should escape all 12783rd party, untrusted content that is injected into your site. This is to prevent, among other issues, 1279<a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Cross-site_scripting">XSS attacks</a>.</p> 1280<p>There is extensive documentation on XSS and how to prevent it on the excellent <a rel="noopener" target="_blank" href="https://owasp.org/www-community/attacks/xss/">OWASP Website</a>, 1281including a <a rel="noopener" target="_blank" href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html">Cross Site Scripting Prevention Cheat Sheet</a>.</p> 1282<p>The good news is that this is a very old and well understood topic, and the vast majority of server-side templating languages 1283support <a rel="noopener" target="_blank" href="https://docs.djangoproject.com/en/4.2/ref/templates/language/#automatic-html-escaping">automatic escaping</a> of 1284content to prevent just such an issue.</p> 1285<p>That being said, there are times people choose to inject HTML more dangerously, often via some sort of <code>raw()</code> 1286mechanism in their templating language. This can be done for good reasons, but if the content being injected is coming 1287from a 3rd party then it <em>must</em> be scrubbed, including removing attributes starting with <code>hx-</code> and <code>data-hx</code>, as well as 1288inline <code><script></code> tags, etc.</p> 1289<p>If you are injecting raw HTML and doing your own escaping, a best practice is to <em>whitelist</em> the attributes and tags you 1290allow, rather than to blacklist the ones you disallow.</p> 1291<h3 id="htmx-security-tools"><a class="zola-anchor" href="#htmx-security-tools" aria-label="Anchor link for: htmx-security-tools">htmx Security Tools</a></h3> 1292<p>Of course, bugs happen and developers are not perfect, so it is good to have a layered approach to
1292security for 1293your web application, and htmx provides tools to help secure your application as well.</p> 1294<p>Letâs take a look at them.</p> 1295<h4 id="hx-disable"><a class="zola-anchor" href="#hx-disable" aria-label="Anchor link for: hx-disable"><code>hx-disable</code></a></h4> 1296<p>The first tool htmx provides to help further secure your application is the <a href="/attributes/hx-disable"><code>hx-disable</code></a> 1297attribute. This attribute will prevent processing of all htmx attributes on a given element, and on all elements within 1298it. So, for example, if you were including raw HTML content in a template (again, this is not recommended!) then you 1299could place a div around the content with the <code>hx-disable</code> attribute on it:</p> 1300<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">div </span><span style="color:#d19a66;">hx-disable</span><span>> 1301</span><span> <%= raw(user_content) %> 1302</span><span></</span><span style="color:#e06c75;">div</span><span>> 1303</span></code></pre> 1304<p>And htmx will not process any htmx-related attributes or features found in that content. This attribute cannot be 1305disabled by injecting further content: if an <code>hx-disable</code> attribute is found anywhere in the parent hierarchy of an 1306element, it will not be processed by htmx.</p> 1307<h4 id="hx-history"><a class="zola-anchor" href="#hx-history" aria-label="Anchor link for: hx-history"><code>hx-history</code></a></h4> 1308<p>Another security consideration is htmx history cache. You may have pages that have sensitive data that you do not 1309want stored in the users <code>localStorage</code> cache. You can omit a given page from the history cache by including the 1310<a href="/attributes/hx-history"><code>hx-history</code></a> attribute anywhere on the page, and setting its value to <code>false</code>.</p> 1311<h4 id="configuration-options"><a class="zola-anchor" href="#configuration-options" aria-label="Anchor link for: configuration-options">Configuration Options</a></h4> 1312<p>htmx also provides configuration options related to security:</p> 1313<ul> 1314<li><code>htmx.config.selfRequestsOnly</code> - if set to <code>true</code>, only requests to the same domain as the current document will be allowed</li> 1315<li><code>htmx.config.allowScriptTags</code> - htmx will process <code><script></code> tags found in new content it loads. If you wish to disable 1316this behavior you can set this configuration variable to <code>false</code></li> 1317<li><code>htmx.config.historyCacheSize</code> - can be set to <code>0</code> to avoid storing any HTML in the <code>localStorage</code> cache</li> 1318<li><code>htmx.config.allowEval</code> - can be set to <code>false</code> to disable all features of htmx that rely on eval: 1319<ul> 1320<li>event filters</li> 1321<li><code>hx-on:</code> attributes</li> 1322<li><code>hx-vals</code> with the <code>js:</code> prefix</li> 1323<li><code>hx-headers</code> with the <code>js:</code> prefix</li> 1324</ul> 1325</li> 1326</ul> 1327<p>Note that all features removed by disabling <code>eval()</code> can be reimplemented using your own custom javascript and the 1328htmx event model.</p> 1329<h4 id="events-1"><a class="zola-anchor" href="#events-1" aria-label="Anchor link for: events-1">Events</a></h4> 1330<p>If you want to allow requests to some domains beyond the current host, but not leave things totally open, you can 1331use the <code>htmx:validateUrl</code> event. This event will have the request URL available in the <code>detail.url</code> slot, as well 1332as a <code>sameHost</code> property.</p> 1333<p>You can inspect these values and, if the request is not valid, invoke <code>preventDefault()</code> on the event to prevent the 1334request from being issued.</p> 1335<pre data-lang="javascript" style="background-color:#1f2329;color:#abb2bf;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span>document.body.</span><span style="color:#56b6c2;">addEventListener</span><span>(</span><span style="color:#98c379;">'htmx:validateUrl'</span><span>, </span><span style="color:#c678dd;">function </span><span>(</span><span style="color:#e06c75;">evt</span><span>) { 1336</span><span> </span><span style="font-style:italic;color:#848da1;">// only allow requests to the current server as well as myserver.com 1337</span><span> </span><span style="color:#c678dd;">if </span><span>(!</span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">sameHost </span><span>&& </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#e06c75;">detail</span><span>.</span><span style="color:#e06c75;">
1337url</span><span>.hostname !== </span><span style="color:#98c379;">"myserver.com"</span><span>) { 1338</span><span> </span><span style="color:#e06c75;">evt</span><span>.</span><span style="color:#56b6c2;">preventDefault</span><span>(); 1339</span><span> } 1340</span><span>}); 1341</span></code></pre> 1342<h3 id="csp-options"><a class="zola-anchor" href="#csp-options" aria-label="Anchor link for: csp-options">CSP Options</a></h3> 1343<p>Browsers also provide tools for further securing your web application. The most powerful tool available is a 1344<a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP">Content Security Policy</a>. Using a CSP you can tell the 1345browser to, for example, not issue requests to non-origin hosts, to not evaluate inline script tags, etc.</p> 1346<p>Here is an example CSP in a <code>meta</code> tag:</p> 1347<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#e06c75;">meta </span><span style="color:#d19a66;">http-equiv</span><span>=</span><span style="color:#98c379;">"Content-Security-Policy" </span><span style="color:#d19a66;">content</span><span>=</span><span style="color:#98c379;">"default-src 'self';"</span><span>> 1348</span></code></pre> 1349<p>This tells the browser âOnly allow connections to the original (source) domainâ. This would be redundant with the 1350<code>htmx.config.selfRequestsOnly</code>, but a layered approach to security is warranted and, in fact, ideal, when dealing 1351with application security.</p> 1352<p>A full discussion of CSPs is beyond the scope of this document, but the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP">MDN Article</a> provides a good jumping-off point 1353for exploring this topic.</p> 1354<h3 id="csrf-prevention"><a class="zola-anchor" href="#csrf-prevention" aria-label="Anchor link for: csrf-prevention">CSRF Prevention</a></h3> 1355<p>The assignment and checking of CSRF tokens are typically backend responsibilities, but <code>htmx</code> can support returning the CSRF token automatically with every request using the <code>hx-headers</code> attribute. The attribute needs to be added to the element issuing the request or one of its ancestor elements. This makes the <code>html</code> and <code>body</code> elements effective global vehicles for adding the CSRF token to the <code>HTTP</code> request header, as illustrated below.</p> 1356<p>Note: <code>hx-boost</code> does not update the <code><html></code> or <code><body></code> tags; if using this feature with <code>hx-boost</code>, make sure to include the CSRF token on an element that <em>will</em> get replaced. Many web frameworks support automatically inserting the CSRF token as a hidden input in HTML forms. This is encouraged whenever possible.</p> 1357<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">html </span><span style="color:#d19a66;">lang</span><span>=</span><span style="color:#98c379;">"en" </span><span style="color:#d19a66;">hx-headers</span><span>=</span><span style="color:#98c379;">'{"X-CSRF-TOKEN": "CSRF_TOKEN_INSERTED_HERE"}'</span><span>> 1358</span><span> : 1359</span><span></</span><span style="color:#e06c75;">html</span><span>> 1360</span></code></pre> 1361<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#e06c75;">body </span><span style="color:#d19a66;">hx-headers</span><span>=</span><span style="color:#98c379;">'{"X-CSRF-TOKEN": "CSRF_TOKEN_INSERTED_HERE"}'</span><span>> 1362</span><span> : 1363</span><span> </</span><span style="color:#e06c75;">body</span><span>> 1364</span></code></pre> 1365<p>The above elements are usually unique in an HTML document and should be easy to locate within templates.</p> 1366<h2 id="config"><a class="zola-anchor" href="#config" aria-label="Anchor link for: config">Configuring htmx</a></h2> 1367<p>Htmx has some configuration options that can be accessed either programmatically or declaratively. They are 1368listed below:</p> 1369<div class="info-table"> 1370<table><thead><tr><th>
1370Config Variable</th><th>Info</th></tr></thead><tbody> 1371<tr><td><code>htmx.config.historyEnabled</code></td><td>defaults to <code>true</code>, really only useful for testing</td></tr> 1372<tr><td><code>htmx.config.historyCacheSize</code></td><td>defaults to 10</td></tr> 1373<tr><td><code>htmx.config.refreshOnHistoryMiss</code></td><td>defaults to <code>false</code>, if set to <code>true</code> htmx will issue a full page refresh on history misses rather than use an AJAX request</td></tr> 1374<tr><td><code>htmx.config.defaultSwapStyle</code></td><td>defaults to <code>innerHTML</code></td></tr> 1375<tr><td><code>htmx.config.defaultSwapDelay</code></td><td>defaults to 0</td></tr> 1376<tr><td><code>htmx.config.defaultSettleDelay</code></td><td>defaults to 20</td></tr> 1377<tr><td><code>htmx.config.includeIndicatorStyles</code></td><td>defaults to <code>true</code> (determines if the indicator styles are loaded)</td></tr> 1378<tr><td><code>htmx.config.indicatorClass</code></td><td>defaults to <code>htmx-indicator</code></td></tr> 1379<tr><td><code>htmx.config.requestClass</code></td><td>defaults to <code>htmx-request</code></td></tr> 1380<tr><td><code>htmx.config.addedClass</code></td><td>defaults to <code>htmx-added</code></td></tr> 1381<tr><td><code>htmx.config.settlingClass</code></td><td>defaults to <code>htmx-settling</code></td></tr> 1382<tr><td><code>htmx.config.swappingClass</code></td><td>defaults to <code>htmx-swapping</code></td></tr> 1383<tr><td><code>htmx.config.allowEval</code></td><td>defaults to <code>true</code>, can be used to disable htmxâs use of eval for certain features (e.g. trigger filters)</td></tr> 1384<tr><td><code>htmx.config.allowScriptTags</code></td><td>defaults to <code>true</code>, determines if htmx will process script tags found in new content</td></tr> 1385<tr><td><code>htmx.config.inlineScriptNonce</code></td><td>defaults to <code>''</code>, meaning that no nonce will be added to inline scripts</td></tr> 1386<tr><td><code>htmx.config.attributesToSettle</code></td><td>defaults to <code>["class", "style", "width", "height"]</code>, the attributes to settle during the settling phase</td></tr> 1387<tr><td><code>htmx.config.inlineStyleNonce</code></td><td>defaults to <code>''</code>, meaning that no nonce will be added to inline styles</td></tr> 1388<tr><td><code>htmx.config.useTemplateFragments</code></td><td>defaults to <code>false</code>, HTML template tags for parsing content from the server (not IE11 compatible!)</td></tr> 1389<tr><td><code>htmx.config.wsReconnectDelay</code></td><td>defaults to <code>full-jitter</code></td></tr> 1390<tr><td><code>htmx.config.wsBinaryType</code></td><td>defaults to <code>blob</code>, the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/docs/Web/API/WebSocket/binaryType">type of binary data</a> being received over the WebSocket connection</td></tr> 1391<tr><td><code>htmx.config.disableSelector</code></td><td>defaults to <code>[hx-disable], [data-hx-disable]</code>, htmx will not process elements with this attribute on it or a parent</td></tr> 1392<tr><td><code>htmx.config.withCredentials</code></td><td>defaults to <code>false</code>, allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates</td></tr> 1393<tr><td><code>htmx.config.timeout</code></td><td>defaults to 0, the number of milliseconds a request can take before automatically being terminated</td></tr> 1394<tr><td><code>htmx.config.scrollBehavior</code></td><td>defaults to âinstantâ, the scroll behavior when using the <a href="https://htmx.org/attributes/hx-swap/#scrolling-scroll-show">show</a> modifier with <code>hx-swap</code>. The allowed values are <code>instant</code> (scrolling should happen instantly in a single jump), <code>smooth</code> (scrolling should animate smoothly) and <code>auto</code> (scroll behavior is determined by the computed value of <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior">scroll-behavior</a>).</td></tr> 1395<tr><td><code>htmx.config.defaultFocusScroll</code></td><td>if the focused element should be scrolled into view, defaults to false and can be overridden using the <a href="https://htmx.org/attributes/hx-swap/#focus-scroll">focus-scroll</a> swap modifier.</td></tr> 1396<tr><td><code>htmx.config.getCacheBusterParam</code></td><td>defaults to false, if set to true htmx will append the target element to the <code>GET</code> request in the format <code>org.htmx.cache-buster=targetElementId</code></td></tr> 1397<tr><td><code>htmx.config.globalViewTransitions</code></td><td>if set to <code>true</code>, htmx will use the <a rel="noopener" target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API">View Transition</a> API when swapping in new content.</td></tr> 1398<tr><td><code>htmx.config.methodsThatUseUrlParams</code></td><td>defaults to <code>["get", "delete"]</code>, htmx will format requests with these methods by encoding their parameters in the URL, not the request body</td></tr> 1399<tr><td><code>htmx.config.selfRequestsOnly</code></td><td>defaults to <code>true</code>, whether to only allow AJAX requests to the same domain as the current document</td></tr> 1400<tr><td><code>htmx.config.ignoreTitle</code></td><td>defaults to <code>false</code>, if set to <code>true</code> htmx will not update the title of the document when a <code>title</code> tag is found in new content</td></tr> 1401<tr><td><code>htmx.config.disableInheritance</code></td><td>disables attribute inheritance in htmx, which can then be overridden by the <a href="https://htmx.org/attributes/hx-inherit/"><code>hx-inherit</code></a> attribute</td></tr> 1402<tr><td><code>htmx.config.scrollIntoViewOnBoost</code></td><td>defaults to <code>true</code>, whether or not the target of a boosted element is scrolled into the viewport. If <code>hx-target</code> is omitted on a boosted element, the target defaults to <code>body</code>, causing the page to scroll to the top.</td></tr> 1403<tr><td><code>htmx.config.triggerSpecsCache</code></td><td>defaults to <code>null</code>, the cache to store evaluated trigger specifications into, improving parsing performance at the cost of more memory usage. You may define a simple object to use a never-clearing cache, or implement your own system using a <a rel="noopener" target="_blank" href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy">proxy object</a></td></tr> 1404<tr><td><code>htmx.config.responseHandling</code></td><td>the default <a href="https://htmx.org/docs/#response-handling">Response Handling</a> behavior for response status codes can be configured here to either swap or error</td></tr> 1405<tr><td><code>htmx.config.allowNestedOobSwaps</code></td><td>defaults to <code>true</code>, whether to process OOB swaps on elements that are nested within the main response element. See <a href="https://htmx.org/attributes/hx-swap-oob/#nested-oob-swaps">Nested OOB Swaps</a>.</td></tr> 1406<tr><td><code>htmx.config.historyRestoreAsHxRequest</code></td><td>defaults to <code>true</code>, Whether to treat history cache miss full page reload requests as a âHX-Requestâ by returning this response header. This should always be disabled
1406when using HX-Request header to optionally return partial responses</td></tr> 1407<tr><td><code>htmx.config.reportValidityOfForms</code></td><td>defaults to <code>false</code>, whether to report form validation errors to the user and focus the first invalid input, matching native form submission (htmx 4 validates forms by default; see <code>hx-validate</code>)</td></tr> 1408</tbody></table> 1409</div> 1410<p>You can set them directly in javascript, or you can use a <code>meta</code> tag:</p> 1411<pre data-lang="html" style="background-color:#1f2329;color:#abb2bf;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#e06c75;">meta </span><span style="color:#d19a66;">name</span><span>=</span><span style="color:#98c379;">"htmx-config" </span><span style="color:#d19a66;">content</span><span>=</span><span style="color:#98c379;">'{"defaultSwapStyle":"outerHTML"}'</span><span>> 1412</span></code></pre> 1413<h2 id="conclusion"><a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">Conclusion</a></h2> 1414<p>And thatâs it!</p> 1415<p>Have fun with htmx! You can accomplish <a href="https://htmx.org/examples/">quite a bit</a> without writing a lot of code!</p> 1416</div> 1417</div> 1418 1419</main> 1420 1421<footer> 1422 <div class="c content wide-content"> 1423 <div class="row"> 1424 <div class="6 col footer-haiku"> 1425 <h2>haiku</h2> 1426 <p><em> 1427 javascript fatigue:<br> 1428 longing for a hypertext<br> 1429 already in hand 1430 </em></p> 1431 </div> 1432 <div class="6 col footer-menu"> 1433 <div><a href="/docs/">docs</a></div> 1434 <div><a href="/reference/">reference</a></div> 1435 <div><a href="/examples/">examples</a></div> 1436 <div><a href="/talk/">talk</a></div> 1437 <div><a href="/essays/">essays</a></div> 1438 <div><a href="https://twitter.com/htmx_org">@htmx_org</a></div> 1439 </div> 1440 </div> 1441 <div class="row" style="text-align: center;"> 1442 <div class="col"> 1443 <img src="/img/bss_bars.png" alt="" style="max-width: 30px; margin-top: 3em;"> 1444 </div> 1445 </div> 1446 </div> 1447</footer>
1448<script async defer src="https://buttons.github.io/buttons.js"></script>
1448 1449</body> 1450</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.