Dave's htmx Live Reference
Page created: 2021-11-27 , updated: 2023-08-27
This live reference is LIVE! Everything actually works and actually submits to a real API. View this page's source to see the living, breathing client-side markup. Use your browser's developer tools (the F12 key) to view the network traffic.
I still like HTMX just as much as I did when I first discovered it. But I was using it in a project that has ended and I have not been keeping up with it. After some soul-searching, I've decided not to finish this page.
Hopefully what is here will remain useful and I'm happy to make small fixes if anyone finds any. -Dave
Currently presented in the exact same order as the reference documentation: https://htmx.org/reference/
Attributes
htmx enhances HTML using attributes prefixed with hx-
.
Because you aren’t writing JavaScript directly, nothing bad will happen
if the htmx library is not present or JavaScript is disabled. Your page
won’t halt due to syntax errors. For this reason, htmx is a perfect
companion for progressively enhancing HTML interfaces.
hx-boost

Causes <a> and <form> tags to make htmx requests, replacing the whole page <body>
contents (innerHTML
) by default.
Here’s a "regular" anchor link to another page and a "boosted" one. When you
click on the boosted link, the contents of the "Foo" page will be requested and
will replace this one. htmx will even discover the <title>
and set it for us.
The address bar will also reflect the new URL.
Only super savvy users will even realize there’s a difference.
It is much more obvious that we’ve done something different when we change the
swap target to an element other than the whole page body
(hx-target="#boost-target")
:
But notice that the address bar is now pointing to the Foo page. If you refresh now, your browser will take you to the Foo page. You should design boosted links so that they make sense even if the user has JavaScript disabled.
Like most htmx attributes, boost is inherited from parent elements. Here, the container
<div>
contains the hx-boost
attribute, so all of the anchors (<a>
) are boosted:
I think hx-boost
is one of the most convenient ways htmx helps support progressive enhancement.
Make your site/application work 100% without any JavaScript at all, then figure out how scripting
the page can make it even better.
hx-confirm

Pops up the standard browser confirm dialog before performing the HTTP request (whatever it may be).
This example has a <form>
that submits a pilot (via POST) to the API’s /danger/zone
.
It has an hx-confirm
attribute that will first prompt to ask you if you wish to do this.
hx-delete

This is what’s super-cool about htmx: it extends HTML to remove arbitrary limitations. Why can the native HTML elements only issue GET or POST requests? We can fix that.
Adding hx-delete="/foo"
to an element causes it to send an HTTP DELETE request
to the URL /foo
.
As with boosting, the element fires the request on the "natural" event (buttons and anchors on click,
forms on submit). You can change this with hx-trigger
.
hx-disable

Putting hx-disable
on an element prevents htmx from doing anything with that element
and any of its child elements. Use this any time you need to shut off htmx processing
at an element level for any reason.
The hx-get
on the following example button doesn’t do anything because the parent
<div>
has hx-disable
:
hx-encoding

By default, HTML form requests are POSTed with application/x-www-form-urlencoded
encoding:
name=Owls+Encoding+Spells&genre=Melodic+Forest+Metal
This is the correct type for most typical form data (text fields, checkboxes, etc.) but there’s a much more appropriate type for uploading forms that include complex data such as file uploads.
The multipart/form-data
content type (see RFC 7578)
which "which can be used by a wide variety of applications and transported by a
wide variety of protocols as a way of returning a set of values as the result
of a user filling out a form."
In fact, when uploading files from HTML forms, encoding with multipart/form-data
is the
only way to send files. Otherwise you’ll just send the selected filename!
Let’s see what that looks like:
-----------------------------221380888523703779353220985036 Content-Disposition: form-data; name="name" Owls Encoding Spells -----------------------------221380888523703779353220985036 Content-Disposition: form-data; name="genre" Melodic Forest Metal -----------------------------221380888523703779353220985036--
As you can see, a multipart form is extreme overkill for transfering regular text form fields like this!
Since I’ve set a limit of 10Kb for uploads to my API, I’ve provided a sample file in the form of a story in a .txt document. By weird coincidence, the story is also about multipart form encoding.
Both forms below use hx-boost
so that htmx makes the request. The encoding
type is set in the second one to use multipart/form-data
with hx-encoding
so you can see the difference. (Normally you’d set this with the enctype
attribute in a <form>
tag (and that’s what I recommend), but having the
ability to add this to any tag with htmx rounds out its ability to address edge
cases and fully enhance HTML.
Sample file to upload:
encoding-owl.txt Encoding Owl Saves the Day
Form with default encoding type:
(Response will show up in box below the second form.)Same form, but with multipart encoding:
(This example also uses the inheritance feature of htmx: the hx-boost
and
hx-target
properties for both forms are set in the parent div.)
hx-ext

You can define extensions to htmx with htmx.defineExtension('foo', …)
. Use them with
the hx-ext="foo, bar"
attribute (note that multiple extensions can be used by separating
them with commas in the attribute value). There are also twelve (as I write this) "official"
extensions that are part of the htmx repo and published in separate .js files - they expose
additional interesting functionality for DOM elements.
Check them out.
The API surface for htmx extensions is really small (just five callback functions available). See the documentation for the details. Also see the events documentation for the htmx events you can handle.
Here we have created an extension called "foo", registered it with
htmx, and activated it on this container div. Any element with a
foo
attribute will pop up an alert box with the element's inner
text.
(no "foo" attribute on this one)
hx-get

The hx-boost
directive (top of this page) tells htmx to make the request on behalf of an
element which would normally do a GET or POST request (anchor and form tags). With
hx-get
, we can cause any element to make a GET HTTP request.
hx-headers

This shows how much control htmx gives us over all aspects of HTTP requests in our HTML attributes. The format of the value of this attribute is interesting: it’s a JSON object containing key-value pairs, each of which will be sent as header properties in the request.

Hey! I don’t need any commentary. The squirrel volunteered to do headers. Nobody else wanted to be the header animal. I didn’t see any of you jumping to demonstrate HTTP headers.

See? There you have it.
hx-history-elt

The hx-history-elt
or "history element" attribute tells htmx to use only the scope of
the current element for history snapshots (which preserve browser navigation history).
To demonstrate this, we’ll need a whole new page!



(And also read the incredible Forest Blog!)




hx-include

The hx-include
attribute tells htmx to include the value from another
element (or elements) on the page in the HTTP request.
In the example below, the Publisher input field is outside of the <form> tag, but it
is included in the request by way of hx-include
. Try it out and you’ll
see that the publisher field (and whatever you typed in it) is part of the request body.
Publisher:
It’s a little difficult to imagine obvious use cases for this and it at first appears to have been included to handle weird edge cases. But actually, I suspect there might be all kind of handy uses for this because it allows you to declaratively tie together data from disparate parts of the HTML document without having to restructure or compromise the "physical" layout of the document to do so.
In this example, an anchor link submits the form by including the form element, which causes child input elements to be included.
Click here to submit the form!
But note that including fields like this is probably going to break whatever fancy thing you had planned if JavaScript isn’t enabled. So this attribute is probably not part of a valid progressive enhancement strategy.
hx-indicator

A very common UI need is some sort of spinner or other "waiting" indicator to
let the user know that their
call is very important to you
request has been submitted to The Cloud.
Thankfully, htmx has this common usage covered with hx-indicator
.
It works by letting you target any element on the page with a CSS selector (typically by ID or class)
or you can also use magic like closest div
or closest img
.
While a request is "in flight", a htmx-request
class is added to the targeted element.
In the example below, I have three <div>
tags with IDs (one for each button).
They all have the tortoise-indicator
class so that they don’t display until they
are needed. As explained above, the htmx-request
class will be added, so that’s
how I make them display as needed. Here’s the CSS:
.tortoise-indicator { display: none; } .htmx-request.tortoise-indicator { display: inline; }



Side note: I made the little tortoise animated GIF featured in the example above in Krita. Using just the official tutorial, I was able to go from knowing nothing to a completed animation in a single evening. Krita is an amazingly polished FOSS application!
hx-params

You can use hx-params
to either exclude (filter) certain parameters from a request.
Or you can use it to include values from nearby form elements as parameters for a method which wouldn’t normally do so such as GET:
By default hx-get does not include any parameters. You can use the hx-params attribute to change this — hx-get reference
I couldn’t actually get the include-in-a-GET to work outside of a <form>
until a reader emailed me and pointed out the magic combo (thanks!).
See the relevant part of this Stack Overflow answer.
The following examples show how you can use the filtering aspect of hx-params
.
You can use wildcards or list fields by name to include:
hx-params="fox1, fox2"and will only submit those fields.
Or you can exclude specific fields:
hx-params="not fox1"and will submit all but that field.
hx-patch

An HTTP PATH request is for updating or changing parts of a document. This is in contrast with PUT, which is for completely replacing a document with a new one.
(HTTP PATCH)
hx-post

Makes the element perform an HTTP POST request when it’s action is triggered (usually
a click). This is just like the GET (hx-get
) we saw above, but it’s a POST instead!
(Posty the Post would like it very much if you would send a POST request with the example below. Thank you.)
hx-preserve
2022-04-28: I’m changing how I continue this! I was creating the technical examples, drawing animals, and writing the creative text all at once. I’ve always found it hard to "shift gears" like this. So I’m going to continue (as of hx-preserve) in more of a phased approach: do all of the technical work (example code) first, then write the creative text, then make a final pass to create the art (probably improving what’s currently there to make it all more consistent).
Put this attribute (and an id
attribute!) on an element. When htmx would normally
replace it with new content, it will instead be preserved (its replacement must have
the same ID).
In the example below, the HTML contenteditable
property has been set on two div
elements. But only the top one has the hx-preserve
property (and an id
). Try
editing the text in both elements and then use the Request Fruit Preserve to get
a fresh set of preserves and see what happens.
hx-prompt
This example is minus the creative stuff. But it does work. This is the last thing I completed.
hx-push-url
This is the last working example.
Here’s the page we’ll be loading below. This is just a regular link: push1.
After clicking this button, look at your browser's URL bar.
Meta: The Show Source links
Wondering how the "Show Source" links work? Click the one in this box to find out!