Elijah Asaolu I am a programmer, I have a life.

Htmx: The newest old way to make web apps

6 min read 1890

HTMX: The Newest Old Way to Make Web Apps


Htmx is a JavaScript library for performing AJAX requests, triggering CSS transitions, and invoking WebSocket and server-sent events directly from HTML elements. Htmx lets you build modern and powerful user interfaces with simple markups.

This library weighs ~10KB (min.gz’d), it is dependency-free (i.e., it does not require any other JavaScript package to run), and it’s also compatible with IE11.

In this tutorial, we will be exploring the powerful features of htmx while covering the following sections:

  • Installing htmx
  • Sending AJAX requests with htmx
  • Custom htmx input validation
  • Triggering CSS animation with htmx

Installing htmx

You can get started with htmx by downloading the htmx source file or including its CDN directly in your markup, like below:

<script src="https://unpkg.com/[email protected]"></script>

The script above loads the current stable version of htmx, which as of writing this is version 1.3.3, on your webpage. Once that’s done, you can implement htmx features on your webpage.

Sending AJAX requests with htmx

Htmx provides a set of attributes that allows you to send AJAX requests directly from an HTML element. Available attributes include:

  • hx-get — send GET request to the provided URL
  • hx-post — send POST request to the provided URL
  • hx-put — send PUT request to the provided URL
  • hx-patch — send PATCH request to the provided URL
  • hx-delete — send DELETE request to the provided URL

Code sample

<button hx-get="http://localhost/todos">Load Todos</button>

The code example above tells the browser that when the user clicks the button, it sends a GET request (hx-get) to the provided URL, which in this case is http://localhost/todos.

Htmx get-request

By default, the response returned from any htmx request will be loaded in the current element that is sending the request. In the In the Targeting elements for AJAX requests section, we will be exploring how to load the response in another HTML element.

Targeting elements for AJAX requests section, we will be exploring how to load the response in another HTML element.

Trigger requests

You should note that AJAX requests in htmx are triggered by the natural event of the element. For example, input, select, and textarea are triggered by the onchange event, and form is triggered by the onsubmit event, and every other thing is triggered by the onclick event.

In a situation where you want to modify the event that triggers the request, htmx provides a special hx-trigger attribute for this:

<div hx-get="http://localhost/todos" hx-trigger="mouseenter">
    Mouse over me!

In the example above, the GET request will be sent to the provided URL if and only if the user’s mouse hovers on the div.

Trigger modifiers

The hx-trigger attribute mentioned in the previous section accepts an additional modifier to change the behavior of the trigger. Available trigger modifiers include:

  • once — ensures a request will only happen once
  • changed — issues a request if the value of the HTML element has changed
  • delay:<time interval> — waits for the given amount of time before issuing the request (e.g., delay-1s). If the event triggers again, the countdown is reset
  • throttle:<time interval> — waits the given amount of time before sending the request (e.g., throttle:1s). But unlike delay, if a new event occurs before the time limit is reached, the event will be in a queue so that it will trigger at the end of the previous event
  • from:<CSS Selector> — listens for the event on a different element

Code sample

    hx-trigger="keyup changed delay:500ms" />

In the code sample provided above, once the user performs a keyup event on the input element (i.e., the user types any text in the input box) and its previous value changes, the browser will automatically send a GET request to http://localhost/search after 500ms.

Polling with the htmx-trigger attribute

In the htmx-trigger attribute, you can also specify every n seconds rather than waiting for an event that triggers the request. With this option, you can send a request to a particular URL every n seconds:

  <div hx-get="/history" hx-trigger="every 2s">

The code sample above tells the browser to issue a GET request to /history endpoint every 2s and load the response into the div.

Targeting elements for AJAX requests

In previous sections, we’d mentioned that the response from an AJAX request in htmx will be loaded into the element making the request. If you need the response to be loaded into a different element, you can use the hx-target attribute to do this. This attribute accepts a CSS selector and automatically injects the AJAX response into an HTML element with the specified selector.

We can modify our to-dos sample to suit this case:

<button hx-get="http://localhost/todos" hx-target="#result">
    Load Todos
<div id="result"></div>

Unlike the previous example, this new code sample sends a request to http://localhost/todos and loads the response in our div with id=result.

Swapping the HTML returned into the DOM

Similar to hx-target, the hx-swap attribute is used to define how the returned AJAX response will be loaded in the DOM. Supported values include:

  • innerHTML — default value, this option will load the AJAX response inside the current element sending the request
  • outerHTML — this option replaces the entire element sending the request with the returned response
  • afterbegin — loads the response as a first child of the element sending the request
  • beforebegin — loads the response as a parent element of the actual element triggering the request
  • beforeend — loads and appends the AJAX response after the last child of the element sending the request
  • afterend — unlike the previous, this appends the AJAX response after the element sending the request
  • none — this option will not append or prepend the response from an AJAX request

Request indicators

When sending an AJAX request, it is often good practice to let the user know that something is happening in the background since the browser won’t do this automatically by default. You can easily accomplish this in htmx with the htmx-indicator class.

Consider the code sample below:

<div hx-get="http://path/to/api">
     <button>Click Me!</button>

The opacity of any HTML element defined with the htmx-indicator class is set to 0 by default, therefore making the element invisible but present in the DOM.

And, when you issue an AJAX request, htmx will automatically add a new htmx-request class to the element sending the request. This new htmx-request class will cause a child element with the htmx-indicator class on it to transition to an opacity of 1, therefore showing the indicator.

htmx-indicator Example

Requesting data

If your AJAX request was triggered by a form or an input element, by default htmx will automatically include the value of all the input field(s) in your request.

But in a case where you want to include the values of other elements, you can use the hx-include attribute with a CSS selector of all the elements whose values you want to include in the request.

Code sample

    <button hx-post="http://path/to/api/register" hx-include="[name=username]">
    Enter Username: <input name="username" type="text"/>

Like in the code sample above, when you issue a request to the /register endpoint, your AJAX request will automatically include the email field in its body.

Filtering out parameters

Htmx also provides another htmx-params attribute with which you can filter out the only parameters that will be submitted when an AJAX request is sent.

<div hx-get="http://path/to/api/example" hx-params="*">
    Send Request

The code sample above will include all input elements on your page as your request parameters.

All possible values include:

  • * — will include all parameters present in your webpage and send it along in your AJAX request
  • none — won’t include any parameters in your request
  • not <param-list> — includes all other parameters and excludes the comma-separated list of parameter names
  • <param-list> — will only include all the comma-separated parameter names in your list

Uploading files

With htmx you can easily send files such as images, videos, PDFs, etc. to your backend for processing by adding the hx-encoding attribute with value multipart/form-data to the parent element of the actual element sending the request:

<form hx-encoding="multipart/form-data">
    Select File:
    <input type="file" name="myFile" />
      Upload File!

Custom htmx input validation

Htmx is integrated with the HTML5 validation API by default, and will not issue a request if a validatable input is invalid. This feature works for both AJAX requests and WebSocket events.

In addition to this, htmx also fires events around validation, which can be pretty useful in custom input validation and error handling.

Available validation events include:

  • htmx:validation:validate — this event is useful in adding custom validation login, as it is called before an element is validated
  • htmx:validation:failed — this event is fired when an element validation returns false, i.e., indicating an invalid input
  • htmx:validation:halted — this event is called when an element was unable to issue a request due to input validation errors

Triggering CSS animation with htmx

Htmx provides a way to easily attach smooth CSS transitions to AJAX events and also in your webpage generally.

Using class-tool

htmx class-tool is an extension that you can easily use to toggle, add, or remove a particular class name from an HTML element without writing any JavaScript code.

You can utilize this extension by adding the classes attribute to your element and then specifying the action, followed by the class name you want to add or remove:

<div classes="add sample-class:1s"></div>

Like in the code sample above, once the browser content is loaded, htmx will automatically add a new class (sample-class) to the div after 1s.

Also note that you can create an action queue by separating each action with a comma (,), or make multiple actions run simultaneously by separating them with an ampersand (&):

<!-- class tool queue -->

<div classes="add sample-class:1s, remove another-class:2s, toggle 3rd-class:1s"></div>

<!-- simultaneous actions -->

<div classes="add sample-class:1s & remove another-class:2s & toggle 3rd-class:1s"></div>

Below is an example that toggles the visibility of an element:

      .demo.faded {
        opacity: 0.3;
      .demo {
        opacity: 1;
        transition: opacity ease-in 900ms;
    <div class="demo" classes="toggle faded:1s">I'm Fading! ⚡</div>

Code Sample Output htmx sample-class


In this article, we’ve explored the htmx installation process, how to send AJAX requests, form validation, and also triggering CSS animation without writing any JavaScript code.

Htmx offers experimental support for WebSocket and server-sent events, which were not covered in this article because they are still under development. You can learn more about WebSocket and SSE support from htmx documentation.

Contribute to htmx on GitHub.

Get set up with LogRocket's modern error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID
  2. Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not server-side
  3. $ npm i --save logrocket 

    // Code:

    import LogRocket from 'logrocket';
    Add to your HTML:

    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • NgRx middleware
    • Vuex plugin
Get started now
Elijah Asaolu I am a programmer, I have a life.

Leave a Reply