Exploring HTMX: building dynamic web apps without JavaScript
Tags: javascript, webdev, htmx
Published: 2022-07-15 10:57:19

by [David Adeneye](https://blog.openreplay.com/authors/david-adeneye)

According to the documentation, the [HTMX](https://htmx.org/) library allows you to add modern browser features without using Javascript. It gives you access to **CSS Transitions**, **AJAX**, **WebSockets**, and **Server-Sent Events** directly in HTML, using attributes to build modern user interfaces quickly. Would it be possible to develop web apps on the client-side without JavaScript? In this tutorial, we will explore all the mind-blowing features of HTMX. You will learn how to send Ajax requests, upload files, validate input, and trigger CSS transitions without writing JavaScript code.

## What is HTMX, and why is it important?

In 2013, Carson Gross created an alternative frontend library [intercooler.js](https://intercoolerjs.org/), with the tagline "Ajax With Attributes" to simplify the complexity of frontend web development. A new version of intercooler.js reached version 2.0 and became [htmx](https://htmx.org/) described as a library that enables you to access Ajax, WebSockets, CSS transition, and Server-Sent Events directly inside HTML.

The HTMX creator says it attempts to leverage HTML's power by using the original model of the web to create web apps. With this approach, developers don't have to write JavaScript to achieve similar functionality. Instead, they use extra HTML attributes to achieve dynamic content and updates. According to Gross, these are the motivation behind htmx: 

* Why should only `<a>` and `<form>` be able to make HTTP requests?
* Why should only `click` & `submit` events trigger them?
* Why should only `GET` & `POST` methods be available? 
* Why should you only be able to replace the `entire` screen? 

"By removing the arbitrary constraints, htmx completes HTML as a hypertext," he concludes.

With HTMX, developers can implement several UI features and UX patterns with minimal HTML and styling such as [Progress Bar](https://htmx.org/examples/progress-bar/ ), [Lazy Loading](https://htmx.org/examples/progress-bar/), [Infinite Scroll](https://htmx.org/examples/infinite-scroll/), [Inline Validation](https://htmx.org/examples/inline-validation/) and [more](https://htmx.org/examples/). 

The HTMX approach differs from other frontend frameworks such as Vue.js and React, where the client-side application uses JavaScript to request information from the server and receive it in a JSON format. With HTMX, when you make a request to the server, the endpoint will return Html fully formed and will update part of the page. You can integrate HTMX with any server-side technology since application logic happens on the backend.


## Setting up HTMX

To setup HTMX, you can seemingly load it via a CDN and add it to your head tag like this below:

```
<script src="https://unpkg.com/htmx.org@1.7.0" integrity="sha384-EzBXYPt0/T6gxNp0nuPtLkmRpmDBbjg6WmCUZRLXBBwYYmwAUxzlSGej0ARHX0Bo" crossorigin="anonymous"></script
```

Another way is to download the [htmx.min.js source file](https://unpkg.com/browse/htmx.org@1.7.0/dist/) and add it to the appropriate directory in your project, then insert it where necessary with a script tag like this :

```
<script src="/path/to/htmx.min.js"></script>
```

You can also install HTMX via `npm` like this below:

```
npm install htmx.org
```


## Sending Ajax Requests using HTMX

HTMX offers a set of attributes that enable you to make AJAX requests directly from HTML. 

* `hx-post` - issues a POST request to the given URL.
* `hx-get` - issues a GET request to the given URL.
* `hx-put` - issues a PUT request to the given URL.
* `hx-patch` - issues a PATCH request to the given URL.
* `hx-delete` - issues a DELETE request to the given URL.
 
Each of these attributes above accepts a URL to send an AJAX request to. So whenever the element is triggered, it sends the specified type of request to the given URL. Consider the example below:


```
<script src="https://unpkg.com/htmx.org@1.7.0"></script>

<div
  hx-get="https://v2.jokeapi.dev/joke/Any?format=txt&safe-mode"
>Load Jokes</div>
```

The demo above instructs the browser that when a user clicks the `Load Jokes` element, it should send a `GET` request (`hx-get`) to the jokeapi endpoint URL (https://v2.jokeapi.dev/joke/Any?format=txt&safe-mode) and load the response into the div element. We used a demo [Joke API](https://v2.jokeapi.dev/#info) here, a REST API that serves uniformly and well-formatted jokes. 

![Htmx-Demo](https://blog.openreplay.com/c58b514080eb196a40a85410fe72eecb/image01.gif)

[Codepen Link](https://codepen.io/davidadeneye/pen/WNMzXxq)

Next, we will examine how to load the response into another HTML element.


### Triggering Requests with HTMX

An element's "natural" event initiates Ajax requests automatically by default. For example, `onchange` event triggers `textarea`, `input`, and `select`. While the `onsubmit` event triggers `form`. The `click` event triggers every other request. HTMX offers a unique 'hx-trigger' if you need to specify which event will trigger the request.

```
<script src="https://unpkg.com/htmx.org@1.7.0"></script>

<div class= "jokes" 
hx-get="https://v2.jokeapi.dev/joke/Any?format=txt&safe-mode" 
hx-trigger="mouseenter”
>
 Load Jokes
</div>
```

![Triggering Request](https://blog.openreplay.com/00b94b7af1d9e1f5f912712320a9bef0/image02.gif)

[CodePen-Link](https://codepen.io/davidadeneye/pen/QWQmXBw)

When the mouse hovers over the div element in the code above, it sends a GET request to the provided URL endpoint and retrieves the Jokes.


### Triggering Modifiers with HTMX

As mentioned in the previous section, it is possible to modify the *hx-trigger* attribute to change its behavior. For instance, if you only want a request to occur once, you can use the `once` modifier for the trigger.

```
<div class= "jokes" 
hx-get="https://v2.jokeapi.dev/joke/Any?format=txt&safe-mode" 
hx-trigger="mouseenter once”
>
      Load Jokes
</div>
```

Below are the lists of available modifiers:

* `changed` - send a request if the element value has changed.
* `display:<time interval>`  - wait for a given amount of time(e.g `delay-1s`) before sending the request.
* `throttle: <time interval>` -  wait the given amount of time (e.g `delay-1s`) before sending the request. Unlike *delay*, if a new event occurs before it reaches the time limit, the event will discard, which means it triggers a request at the end of the time. 

* `form`: `<css selector>` - listen for event on a different element. You can use this for things like keyboard shortcuts.

You can use all these attributes above for implementing some common UX patterns like the Active Search Box pattern. With this [example here](https://htmx.org/examples/active-search/), you can see these attributes above in action.


### Polling with the `htmx-trigger` attribute

Using the HTMX trigger attribute, we can also specify that the element polls the given URL every `n` seconds instead of waiting for an event to occur.

```
<script src="https://unpkg.com/htmx.org@1.7.0"></script>

<div class= "jokes" hx-get="https://v2.jokeapi.dev/joke/Any?format=txt&safe-mode" hx-trigger="every 3s">
      Load Jokes
</div>
```


Here, the HTMX instructs the browser to send a GET request to the `/V2.jokeapi` URL every 3s and display the response in the div element.

![Polling with HTMX](https://blog.openreplay.com/d22a561248362ea41b64f08c79fda04a/image03.gif)

[CodePen-Link](https://codepen.io/davidadeneye/pen/abqGObx)



### Request Indicators

Because the browser provides no feedback, it is helpful to notify users that something is happening. You can do this with HTMX by using the 'htmx-indicator' class.

```
<div class= "jokes" hx-get="https://v2.jokeapi.dev/joke/Any?format=txt&safe-mode" >
 <button>Load Jokes</button>
 <img class="htmx-indicator" src="https://i.imgur.com/8THYvPQ.gif">
</div>
```

The 'htmx-indicator' class would set the opacity of any element with this class to `0` by default, making it hidden but present in the DOM. When you click the 'load jokes' button, it adds the 'htmx-request' class, which displays the loader indicator.

![Request-Indicators](https://blog.openreplay.com/e855d618f5dac585383c9347cc7a3b5d/image04.gif)

[CodePen-Link](https://codepen.io/davidadeneye/pen/eYVrpxg)



### Targeting Elements

As stated before, HTMX loads the response to an AJAX request into the element that initiated the request. The 'hx-target' attribute allows you to load the response in a different element than the one that initiated the request. The 'hx-target' will accept a CSS selector and will automatically load the AJAX response into the target element:


```
<button class="btn" hx-get="https://v2.jokeapi.dev/joke/Any?format=txt&safe-mode" hx-target="#result" > Load Jokes
 
</button>
<div class= "jokes" id="result"></div>
```

In the demo above, when you click on the `load jokes` button, it will automatically load the response into the `div` element below it.

![htmx_target](https://blog.openreplay.com/6183508abbd14559abf24aef1319365f/image05.gif)

[CodePen-Link](https://codepen.io/davidadeneye/full/dydeJRw)

### Swapping



Like the `hx-target` in the previous section, HTMX offers a different way to determine how to load the response returned by Ajax within the Dom. You can do so by setting the 'hx-swap' attribute with any of the values listed below:

* `innerHTML`: This is the default value; it inserts the content into the target element sending the request.
`outerHTML`: It replaces the entire target element with the returned content.
* `afterbegin`: It prepends the response before the first child inside the target element.
* `beforebegin`: prepends the response as a parent element of the actual element triggering the request.
* `beforeend`: It appends the response after the last child of the element sending the request.
* `afterend`: like the `beforeend`, this appends response after the element sending request.
* `none`: this option doesn't append or prepend a response from an AJAX request.

Here is an example of a scrolling progress bar using some of the attributes mentioned above (https://htmx.org/examples/progress-bar).


## Synchronizing Request with HTMX

Sometimes, you will need to synchronize requests between two elements. Suppose you want a request from one element to override another element's requests, or you want to wait until the other element's requests are complete. You can do this by using the `hx-sync` attribute. Consider the code below:

```
<form hx-post="/article">
    <input id="title" name="title" type="text" 
        hx-post="/validate" 
        hx-trigger="change"
    >
    <button type="submit">Submit</button>
</form>
```

In the example above, we have a form submission and an individual `input` validation request. Without using `hx-sync`, when you fill out the form and submit it, it triggers two parallel requests to `/change` and `/validate` simultaneously. According to the documentation, using `hx-sync=" closest form:abort" ` on the input will watch for requests on the `form` and halt the input requests if a form request is present or start while the input request is in flight:

```
<form hx-post="/article">
    <input id="title" name="title" type="text" 
        hx-post="/validate" 
        hx-trigger="change"
        hx-sync="closest form:abort"
    >
    <button type="submit">Submit</button>
</form>
```

Using this approach, we can fix the synchronization issue between the two elements declaratively. You can read more on `hx-sync` attribute  [here](https://htmx.org/attributes/hx-sync/).



## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://static.openreplay.com/images/banner-blog.png)

_Start enjoying your debugging experience - [start using OpenReplay for free](https://github.com/openreplay/openreplay)._




## File Upload with HTMX

With HTMX, you can create a file upload form that will be submitted via Ajax to your backend for processing. You can effortlessly send files like videos, images, and documents. You can implement this with HTMX by directly embedding the `hx-encoding` attributes with the value `multipart/form-data` into the parent element sending the request:

```
<form hx-encoding='multipart/form-data' hx-post='/registration'
          _='on htmx:xhr:progress(loaded, total) set #progress.value to (loaded/total)*100'>
        <input type='file' name='userFile'>
        <button>
            Upload File
        </button>
   </form>
```

## Input Validation with HTMX

Htmx incorporates natively with the HTML 5 Validation API, so if a validatable input is invalid, it will not send a request. This feature applies to both AJAX requests and WebSockets sends. Also, HTMX fires events around validation that you can use to hook in custom validation and error handling. The following events are currently available:

* `htmx:validation: validate – used for adding custom validation logic.
* `htmx`:validation:failed` – this event fires when an element validation return false, e.g., indicating an invalid input.
* `htmx:validation: halted`: It calls this event when you a request is not issued due to validation errors. You can find specific errors in the `event.detail.errors` object.

Consider an input that uses the `htmx:validate:validate` event to ensure that the input has the value `David` using [hyperscript](https://hyperscript.org/):


```
<form hx-post="/validate">
 <input _="on htmx:validation:validate
 if my.value != 'David'
 call me.setCustomValidity('Please enter the value David')
 else
 call me.setCustomValidity('')"
 name="username"
 >
</form>
```

It is important to note that all client-side validation must occur on the server, as it can always be bypassed.


## CSS animations with HTMX

Htmx enables you to use [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions) to add smooth animations and transitions to your web page using only CSS and HTML without JavaScript. HTMX offers a powerful animation extension called `class-tools` which allows you to define CSS classes that swap onto or off the element using the `classes` or `data-classes` attribute.  

You can use the extension by assigning to the `classes` attribute to an element. The `classes` attribute value consist of "runs" separated by an & character. In a run, it will apply class operations sequentially with the specified delay. These class operations are `add`, `remove`, or `toggle` accompanied by a CSS class name and optionally by a colon: and time delay.

```
<div classes= “add sample-demo: 1s”></div>
```

Once the browser contents load, HTMX will automatically add a new class of `sample-demo` to the div after 1 second. Let's take a look at this demo example below:

```
<div hx-ext="class-tools">
 <div class="demo" classes="toggle faded:1s">See me Fading Away </div>

</div>

```

![htmx_transition](https://blog.openreplay.com/5f4b342f196fb3d519cf7b1e69b66afd/image06.gif)

[CodePen-Link](https://codepen.io/davidadeneye/full/NWyMzMY)
You can learn more about how to do compelling animation and transition with HTMX [here](https://htmx.org/examples/animations/).

HTMX seamlessly integrates with different server-side frameworks, although some frameworks may have alternatives for installing HTMX. Check out this [link](https://htmx.org/server-examples/) to explore how you can integrate HTMX with different server-side frameworks.




## Conclusion

HTMX is an incredible technology, and I'm excited about it and can't wait to use it in production on my next project. In this tutorial, we explored how to install HTMX, send Ajax requests, upload files, validate input, and create CSS transitions without using javaScript on the client-side.

Check this [link](https://htmx.org/examples/) to explore some sets of **UX patterns** demo implemented with HTMX that you can edit and integrate with your projects.

The following link (https://htmx.org/examples/) contains some sets of  **UX pattern** demos that you can edit and integrate into your projects.

## Reference

[HTMX Documentation](https://htmx.org/)

[![newsletter](https://blog.openreplay.com/static/e6b18eda7a327511296a2f27692f9c70/e9957/newsletter.png)](https://newsletter.openreplay.com/)