François Constant logo

Productive frontend with HTMx

September 2023

There are nowadays many ways to build websites. If you find the latest trends impractical - as they take too much time and effort - you might be happy to hear about htmx.
This article omits static site generators and online hosted website all together. This article is about websites with end-user functionalities (login, search, CRUD operations, etc.).

Three main approaches to web development

1 The classic approach (limited interactivity)

Most websites are built by simply having the server rendering pages one by one. In other words, when the user goes to mysite.com/about, the server receives a request to render the full about page and returns it; it returns the full HTML for it (including the menu, the footer, etc.).

Often developers add a bit of Javascript when it feels necessary. In that case, the Javascript code is added to some pages as an extra.

2 The current (2023) accepted approach

For about ten years, many developers insist that having an API and separating the frontend and the backend is the way to go. Anyone building a website the “classic way” has become a moron who must ultimately change their mind or be eliminated.

On paper, the backend / frontend separation via an API is indeed beautiful. On one end, the backend deals with the database, the business logic, the permission, the caching… The backend exposes useful data and operations via an API (usually REST or GraphQL). The frontend application is completely separated and runs in the browser directly. The frontend application takes care of the design and the user interactions. It should not contain any business logic.

With an API and a separate frontend application, there is a clear separation of concern. The API can then be used for other things too, such as an Android and an iPhone app. Since the frontend application runs in the browser, it has to be written in (or compiled to) Javascript. This allows developers to write websites that feels more like apps. For example, when a user want to see the about page, a frontend app can show a loading animation, retrieve its content only (not the full HTML page), and swap the content with an animation.

3 The htmx approach

The idea behind htmx is to complete HTML with what’s now missing. What’s missing is some interactivity - i.e. a way to load bits of data - not full pages (yes, this is an over-simplification). With htmx, the bulk of the work remains on the server side.

Here is the explanation copied from the original site:

htmx is a library that allows you to access modern browser features directly from HTML, rather than using javascript.

To understand htmx, first lets take a look at an anchor tag: <a href="/blog">Blog</a>

This anchor tag tells a browser:

“When a user clicks on this link, issue an HTTP GET request to /blog and load the response content into the browser window”.

With that in mind, consider the following bit of HTML:

    <button 
      hx-post="/clicked"
      hx-trigger="click"
      hx-target="#parent-div"
      hx-swap="outerHTML"
    >
      Click Me!
    </button>

This tells htmx:

“When a user clicks on this button, issue an HTTP POST request to ‘/clicked’ and use the content from the response to replace the element with the id parent-div in the DOM”

htmx extends and generalizes the core idea of HTML as a hypertext, opening up many more possibilities directly within the language […].Note that when you are using htmx, on the server side you typically respond with HTML, not JSON. This keeps you firmly within the original web programming model, using Hypertext As The Engine Of Application State without even needing to really understand that concept.

Separate frontend application VS htmx (approach 2 VS 3)

Having a separate backend and frontend generates lots of duplication. The same concepts must be coded twice. For an ecommerce site for exaample, both the backend and the frontend must have models for users, products, a cart, etc. With htmx, there is no code duplication.

With a separate frontend, developers must work with two completely different languages and stacks (or worse, the backend is built in Javascript). With htmx, all the code lives in one stack and developers can take advantage of the programming language of their choice.

With a separate frontend, full-stack functional tests are impractical to write. It’s possible to use tools like Cypress but that requires extra work. The developer writing the tests must be proficient in both stacks. Also, it’s important to note that Cypress tests are really slow. With htmx, since the backend returns HTML for both regular and htmx requests, full-stack unit-testing is trivial and relatively fast (obviously still slower than specific unit-tests).

Finally, with a frontend framework, you need to do extra work for SEO; again, this is not an issue with htmx.

As you can tell, I like working with htmx rather than with a Javascript library or framework like Angular or React. All that being said, htmx is not perfect.

htmx drawbacks

htmx is good for basic interactions only. For more complicated UI, you would still need a separate frontend like React. Even for simple things; if you add lots of htmx tags everywhere, the code might get tricky to read. These are the only drawbacks I’ve found so far.

htmx will be enough for most websites / pages. You will need something else for specific widget and/or for full-on applications like graph editors.

Conclusion

Having a completely separate frontend often does not make practical sense as it takes three times more work. Instead of adding bits of React or JQuery in various screens when some interactivity is required; we can now use htmx and add these bits of interactivity directly in the HTML and in our usual backend code. This way takes less time, allows better unit-testing and keeps thing simple. I highly recommend you to try htmx.