Showing posts with label htmx. Show all posts
Showing posts with label htmx. Show all posts

Ben Nadel on HTMX

Mike's Notes

The Pipi 9 CMS Engine (CMS) uses HTMX in the rendered User Interface (UI). HTMX interacts directly with the DOM.

Recently, Ben Nadel has been running a fascinating series of posts on his blog about his coding experiments with HTMX.

He shares a lot of CFML code on his blog, which is freely reusable. I learn a lot from Ben.

I will update this page with additional references to Ben's HTMX posts.

There is a repository on GitHub for this experiment.

Resources

References

  • Hypermedia Systems by Carson Gross

Repository

  • Home > Ajabbi Research > Library > Subject > CFML
  • Home > Ajabbi Research > Library > Authors > Ben Nadel
  • Home > Handbook > 

Last Updated

10/1/2026

Ben Nadel on HTMX

By: Ben Nadel
bennadel.com: 2025

A Passionate Web Developer With 26 Years Experience.

"I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self! - Ben Nadel"

You Can CMD+Click To Submit A Form To A New Browser Tab

By Ben Nadel on May 29, 2025

In the past couple of months, I've been digging into the HTMX JavaScript framework as a way to layer dynamic client-side functionality on top of my ColdFusion applications. I'm enamored with HTMX; but, unlike as with other frameworks such as Angular or Svelte, HTMX doesn't want to be an end-to-end holistic solution. Which means, I—as the developer—have to make a lot of decisions about where logic should live; and, whether or not something is a good idea. This is turning out to be a lot harder than I first imagined...

read more

Creating An hx-event Extension For Triggering Events In HTMX

By Ben Nadel on May 21, 2025

I'm still very deep in the "learning phase" of using HTMX, trying to understand how things are wired together and where the jagged edges might be. As a code kata, I wanted to see if I could create an HTMX extension that would trigger an event instead of an AJAX call. This way, I might be able to click on a button and bubble a synthetic event up the DOM (Document Object Model) tree to another element that is using an hx-on:{event} binding...

read more

Considering The Functional Requirements Of A Modal Window In An HTMX Web App

By Ben Nadel on May 17, 2025

To start with, I'm not a huge fan of modal windows in a web application. InVision used a ton of modal windows; and it felt like we painted ourselves into a corner that we couldn't get out of. My ambiguity on the matter has only been hardened by articles such as "we use too many damn modals", "modalz modalz modalz", and "who's afraid of a hard page load". That said, modals—and modal-adjacent experiences—do have their place. And, as I start to think about this experience in the context of an HTMX-powered web app, I wanted to come up with a set of functional requirements that I could aim for...

read more

Using A No-Content URL To Help Manage DOM Caching In HTMX And ColdFusion

By Ben Nadel on May 14, 2025

When you hx-boost / AJAX'ify your ColdFusion application with HTMX, HTMX will cache the state of the DOM (Document Object Model) as you navigate from page to page. This way, when you hit the browser's back button, HTMX can restore the previous DOM state, pulling it out of the LocalStorage API. The caveat being, HTMX only does this in response to an AJAX request. Which means, if we want to cache the current state of the DOM, we must issue an AJAX request and we must change the URL...

read more

HTMX Extensions Have Access To An Extended API

By Ben Nadel on May 12, 2025

The HTMX JavaScript framework exposes a public API that is a mixture of convenience methods, such as htmx.on() for event-binding; and framework-specific methods, such as htmx.process() for initializing externally-loaded HTML fragments. When creating an extension in HTMX, the extension's init() method is passed an api argument. At first, I thought this was just an abstracted reference to the aforementioned public API. But, upon further inspection, this reference contains an extended API to help specifically with HTMX extension authoring...

read more

What Happens When You Mutate The DOM Outside Of HTMX

By Ben Nadel on May 10, 2025

In a previous post, I looked at using Alpine.js inside an HTMX application. Since Alpine.js uses the MutationObserver API to observe changes within the Document Object Model (DOM) structure, it doesn't much matter where mutations are initiated. HTMX, however, isn't quite so dynamic. As such, I wanted to sanity check what happens when DOM mutations are initiated outside of the HTMX life-cycle...

read more

Returning JavaScript Tags In HTMX And ColdFusion

By Ben Nadel on May 8, 2025

The primary mechanic of HTMX is swapping out branches of the DOM (Document Object Model) in response to user interactions. Yesterday, however, I had to update a bunch of form inputs based on a <select> change. I wasn't sure how to do this in the cleanest "HTMX Way". Eventually, I settled upon a happy medium in which I use HTMX to execute one-off JavaScript task via an Out of Band (OOB) swap of a <script> tag...

read more

Using Stale-While-Revalidate Cache-Control Headers In HTMX And ColdFusion

By Ben Nadel on May 6, 2025

In my ColdFusion applications, unless I'm generating dynamic images that need to be cached, I almost never use the Cache-Control HTTP headers. Historically, all of my "caching needs" for perceived performance have been handled in my client-side Angular controllers. But, the HTMX JavaScript framework is all about leaning on the web platform to drive application mechanics. As such, I wanted to see how I might use the stale-while-revalidate response directive to boost performance in an HTMX and ColdFusion application...

read more

Keyboard Command Extension In HTMX And ColdFusion

By Ben Nadel on May 3, 2025

Earlier this week, I took a look at using extensions in an HTMX and ColdFusion application. Extensions allow us to tap into the event life-cycle of nodes withing the document object model (DOM); which, in turn, allows us to augment the document behavior as HTMX swaps content into and out of the rendered page. For this follow-up post, I take inspiration from the Docket app by Mark Story. Mark's HTMX and PHP app allows keyboards events to trigger DOM interaction. I wanted to try building something similar for a ColdFusion demo...

read more

Exploring Extensions In HTMX

By Ben Nadel on May 1, 2025

The HTMX JavaScript framework operates by traversing your Document Object Model (DOM) looking for elements that match a set of criteria, such as the existence of an hx-get or an hx-post attribute; and then, processes the matching elements by applying new behaviors. As it orchestrates these modifications, it emits a series of events on the DOM. Informally, these events can be a way for any JavaScript library to hook into the HTMX life-cycle by consuming the DOM as an event-bus; but, HTMX also provides an official way of doing this by using extensions...

read more

Using :scope To Identify The Host Element In .querySelectorAll()

By Ben Nadel on April 29, 2025

Here's a helpful tip that I learned the other day. When using a Document Object Model (DOM) method to query for HTML elements using a CSS selector (ex, .querySelectorAll()), the :scope pseudo-class can be used to identify the host element on which the method is being called. This allows us to use the direct descendant selector (>) to target children of the host element...

read more

Using hx-preserve To Persist Elements Across Swaps In HTMX

By Ben Nadel on April 27, 2025

With HTMX, you can use the hx-boost attribute to AJAX'ify navigation in your ColdFusion applications. Boosting pages increases the complexity of the application and can lead to some strange JavaScript behaviors. But, this trade-off in complexity ushers in the ability to maintain some state across pages. And one way to maintain state in HTMX is with the hx-preserve attribute...

read more

Previous / Next <CSS Selector> Both Use A Depth-First Algorithm In HTMX

By Ben Nadel on April 26, 2025

In the HTMX JavaScript framework, the hx-target attribute can reference other elements in the DOM (Document Object Model) by using CSS selectors, convenience keywords (such as this and next), and a combination thereof. Most of these are relatively straightforward; but, I ran into surprising results when using previous {CSS selector} and next {CSS selector}. I had read the documentation and interpreted it as meaning that the targeted elements were direct descendants of the same parent element. But, this is incorrect. Internally, HTMX is using a depth-first traversal algorithm—from the document root—to find the target nodes; and then, selects the one closest to the trigger element based on a depth-first node traversal order...

read more

Fetch API Will Propagate Non-POST Methods Upon Redirect

By Ben Nadel on April 26, 2025

In the book Hypermedia Systems by Carson Gross, the authors mention that the browser will propagate the HTTP Method upon redirect. In all my years of programming, I had never seen this; so, I sanity checked it and put the issue to rest in my head. Then, yesterday, I was listening to the Remote Ruby podcast with Chris Oliver and Andrew Mason, and they too mentioned this HTTP method propagation specifically for the JavaScript fetch() API. I feel like I was taking crazy-pills; so, I went to sanity check it again; and, discovered that the fetch() API will propagate the HTTP method; but, only for non-GET/POST methods...

read more

Using Alpine.js In HTMX

By Ben Nadel on April 25, 2025

The HTMX JavaScript framework allows us to move a lot of state management out of the browser and back into the ColdFusion server where the "source of truth" resides. But, not all interactions—and not all state—need to be sourced from the server. In such cases, we can use Alpine.js to provide light-weight state management and event binding in the browser. That said, both HTMX and Alpine.js want to "manage the DOM" and the event-bindings. As such, it's not obvious that they'll play well together. To get a sense of where the points-of-friction might lie, I wanted to put together a small demo that uses both HTMX and Alpine.js as well as the hx-boost attribute to "AJAX'ify" the page navigation

read more

Filtering HX-Trigger Server Events In HTMX And ColdFusion

By Ben Nadel on April 22, 2025

When building Single-Page Applications (SPA) with Angular and ColdFusion, one common pattern that I used was to return an event in every mutation-based API response. This event was then triggered on a client-side event-bus; and, various Angular components could respond to it as needed. In an HTMX multi-page application (MPA), we can use the HTTP response header, HX-Trigger, to achieve similar outcomes. And, we can use the filtering capabilities of the client-side hx-trigger attribute to limit the scope of this client-side response...

read more

Conditionally Preventing HX-Boost In HTMX Using An Extension

By Ben Nadel on April 19, 2025

In an HTMX application, the built-in hx-boost attribute tells HTMX to intercept all form and anchor interactions and "AJAX'ify" them. That is, prevent the default browser behavior and re-implement it using AJAX and the History API in order to side-step a full page-load. This is a neat feature; but, it doesn't have any hooks (that I can find) to conditionally prevent hx-boost from acting on a given link. Such a hook would be necessary when integrating content that comes out of a content management system (CMS). To try and add such a hook, I've created my first HTMX extension, prevent-boost, that can conditionally prevent boosting based on RegEx patterns and / or filter callbacks...

read more

Comparing Undefined Values With Optional Chaining In JavaScript

By Ben Nadel on April 17, 2025

Yesterday, while working on some HTMX experiments, I stumbled upon a feature of JavaScript that I didn't known: the undefined value, when compared to Booleans and numbers, always returns false. I've always thought of undefined as a falsy value (which it is); so, I was very surprising to see that undefined did not soft equal false. But, this turns out to be hugely beneficial when it comes to the optional chaining operator (aka, the safe navigation operation) in JavaScript...

read more

HTTP GET And HTTP POST Are Sufficient (For Me) In ColdFusion

By Ben Nadel on April 14, 2025

As of this writing, HTML supports two different HTTP methods: GET and POST. And for the last 25-years, I've been building web-based applications very successfully on top of these two operation. Many people, however, are not satisfied with these limitations; and, would like to see PUT, PATCH, and DELETE added to the list of natively supported methods in HTML. Personally, I'm quite satisfied with GET and POST and haven't really experience any pain-points. So, I thought it might be interesting to try and articulate my perspective....

read more

ColdFusion And HTMX Contact App

By Ben Nadel on April 13, 2025

A couple of weeks ago, I read Hypermedia Systems by Carson Gross. The book is an introduction to HTMX - a JavaScript library that extends the HTML specification and brings dynamic single-page application (SPA) type features to a traditional multi-page application (MPA) architecture. Some of the aspects of HTMX are fairly simple; but, some require a sizable mindset shift. As such, I thought it would be helpful (for me) to take the "contacts app" that Carson builds in the book and translate it into a ColdFusion application context.... 

read more

Hypermedia Systems By Carson Gross

By Ben Nadel on February 18, 2025

Last week, Peter Amiri - maintainer of the CFWheels framework for ColdFusion - sent me a hardcover copy of Hypermedia Systems by Carson Gross, Adam Stepinski, and Deniz Akşimşek. This book argues for the benefits of "Hypermedia Driven Applications" (HDA); and how leaning into the foundational nature of the web as a unified interface and hypermedia platform makes applications easier to build and more accessible while still achieving a high-bar of interactivity. This book is clear, concise, and quite compelling. Coming in at around 300 pages, I finished reading it in two day—I just couldn't put it down.....

read more

HTMX history and the back button

Mike's Notes

I have been building a ribbon UI component and experimenting with different ways to do this. You can go and try them out.

  • Version 1 (Uses CSS, tabs not stable)
  • Version 2 (Uses HTMX)
  • Version 3 (Uses CSS and HTMX; tabs not stable)
  • Version 4 (Uses CSS and HTMX, tabs are stable, and the back button works)

Version 4 is OK.

To get the browser back button to work, I added the meta HTML code below

Resources

References

  • Reference

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

18/05/2025

HTMX history and the back button

By: Mike Peters
On a Sandy Beach: 18/09/2024

Mike is the inventor and architect of Pipi and the founder of Ajabbi.

Code

<meta name="htmx-config" content='{"refreshOnHistoryMiss":"true"}' />

Dynamic Web Apps without JavaScript - HTMX Showcase at DjangoCon and Devoxx

Mike's Notes

Discovering this presentation at QCon solved many problems and simplified the building of the Pipi UI.

Resources

References

  • Architectural Styles and the Design of Network-based Software Architectures by Roy Fielding

Repository

  • Home > Ajabbi Research > Library >
  • Home > Handbook > 

Last Updated

17/05/2025

Dynamic Web Apps without JavaScript - HTMX Showcase at DjangoCon and Devoxx

By: Bruno Couriol
InfQ.com: 21/10/2022

DjangoCon and Devoxx Belgium recently reported examples of interactive web applications developed without JavaScript developers. The showcased htmx HTML-first framework seems to target those applications that mainly propose a friendly interface to CRUD operations over remote resources. In one case, the team was able to remove the JavaScript developer.

At DjangoCon 2022, David Guillot reported reimplementing his company’s SaaS product with HTML-first framework htmx in two months with the following results:

Guillot gladly mentioned that 15,000 lines of JavaScript code disappeared from the codebase; performance improved (as measured by time to interactive and memory usage); the only JavaScript developer in the team left and back-end developers turned to full stack developers.

The htmx team however warns that such spectacular results were achieved because this particular SaaS application was a good fit for htmx’s HTML-first approach:

These are eye-popping numbers, and they reflect the fact that the Contexte application is extremely amenable to hypermedia: it is a content-focused application that shows lots of text and images. We would not expect every web application to see these sorts of numbers.

However, we would expect many applications to see dramatic improvements by adopting the hypermedia/htmx approach, at least for part of their system.

At Devoxx Belgium 2022, Wim Deblauwe showcased the kind of interactivity that htmx can implement without any JavaScript: search-as-you-type input field, update of the user interface as some remote resource is affected by CRUD operations, regularly refresh the user interface with server-sent data, and more.

The htmx team considers an application a good fit for the framework if the UI is mostly text and images; the UI mostly interfaces CRUD operations; and HTML updates mostly take place within well-defined blocks. Conversely, applications with many, dynamic interdependencies, that require offline functionality, or update state extremely frequently would not be a good first for htmx’s hypermedia approach.

In an htmx application, the server returns pages or fragments of pages.

<button hx-post="/clicked"

    hx-trigger="click"

    hx-target="#parent-div"

    hx-swap="outerHTML">

    Click Me!

</button>

The previous HTML excerpt encodes that when a user clicks on the button, htmx issues an HTTP POST request to the /clicked endpoint. Htmx uses the content from the posterior response to replace the element with the id parent-div in the DOM. With htmx, any element (i.e., not just anchors and forms), any event can trigger an HTTP request. The HTML response from the server only updates the relevant part of the UI. For the full overview of htmx capabilities, developers may refer to the documentation.

Interestingly, htmx is often showcased by back-end developers who belong to non-JavaScript ecosystems (e.g., Python/Django/Flask, PHP/Laravel, Ruby/Ruby on Rails). As Guillot mentioned, with htmx, back-end developers extend their scope to the entire stack without having to learn JavaScript, npm, Webpack, React, CSS-in-JS, and many more. Matt Layman, in his You don’t need JavaScript talk summarizes:

"It’s just this constant churn in the [JavaScript] ecosystem and adding a lot of complexity onto a flow when you’re trying to deliver a web application. You want to just get an experience out there that actually works for people. But then you end up fighting with [the toolchain].

At a certain amount of scale, JavaScript can be a fantastic thing to build into your applications. But for an average person or a small team, it’s a ton of extra complexity so my recommendation is: just don’t. We have other options."

htmx is an open-source project under the BSD-2-clause license.

htmx claims to provide AJAX, CSS Transitions, WebSockets, and Server-Sent Events directly in HTML, using attributes, so developers can build user interfaces with the simplicity and power of hypertext.

HTMX

Let’s look at the first feature of htmx: the ability of any web page element to issue HTTP requests. This is the core functionality provided by htmx, and it consists of five attributes that can be used to issue the five different developer-facing types of HTTP requests:

hx-get

Issues an HTTP GET request.

hx-post

Issues an HTTP POST request.

hx-put

Issues an HTTP PUT request.

hx-patch

Issues an HTTP PATCH request.

hx-delete

Issues an HTTP DELETE request.

hx-target

Relative Positional Expressions in Htmx.
  • next - Scan forward in the DOM for the next matching element, e.g., next .error
  • previousScan backwards in the DOM for the closest previous matching element, e.g., previous .alert
  • closest - Scan the parents of this element for the matching element, e.g., the closest table.
  • find - Scan the children of this element for matching element, e.g., find the span.
  • this - the current element is the target (default)

hx-swap

The hx-swap attribute supports the following values:

  • innerHTML - The default, replace the inner html of the target element.
  • outerHTML - Replace the entire target element with the response.
  • beforebegin - Insert the response before the target element.
  • afterbegin - Insert the response before the first child of the target element.
  • beforeend - Insert the response after the last child of the target element.
  • afterend - Insert the response after the target element.
  • delete - Deletes the target element regardless of the response.
  • none - No swap will be performed.
  • settle -Like swap, this allows you to apply a specific delay between when the content has been swapped into the DOM and when its attributes are “settled”, that is, updated from their old values (if any) to their new values. This can give you fine-grained control over CSS transitions.
  • show - Allows you to specify an element that should be shown — that is, scrolled into the viewport of the browser if necessary — when a request is completed.
  • scroll - Allows you to specify a scrollable element (that is, an element with scrollbars), that should be scrolled to the top or bottom when a request is completed.
  • focus-scroll - Allows you to specify that htmx should scroll to the focused element when a request completes. The default for this modifier is “false.”

hx-include


hx-vals


hx-push-url

“Pushes” the request URL (or some other value) into the navigation bar.

hx-location

Causes a client-side redirection to a new location

hx-preserve

Preserves a bit of the DOM between requests; the original content will be kept, regardless of what is returned.

hx-sync

Synchronized requests between two or more elements.

hx-disable

Disables htmx behavior on this element and any children. We will come back to this when we discuss the topic of security.

hx-boost


hx-confirm


hx-indicator

Let the user know that a search is in progress.

HTTP Request

When placed on an element, each attribute tells the htmx library: “When a user clicks (or whatever) this element, issue an HTTP request of the specified type.”

HX-Boosted

This will be the string “true” if the request is made via an element using hx-boost.

HX-Current-URL

This will be the browser's current URL.

HX-History-Restore-Request

This will be the string “true” if the request is for history restoration after a miss in the local history cache.

HX-Prompt

This will contain the user response to an hx-prompt.

HX-Request

This value is always “true” for htmx-based requests.

HX-Target

This value will be the id of the target element if it exists.

HX-Trigger-Name

If it exists, this value will be the name of the triggered element.

HX-Trigger

If it exists, this value will be the ID of the triggered element.
once. The given event will only trigger a request once.
  • delay - Allows you to specify a delay to wait before a request is issued. If the event occurs again, the first event is discarded and the timer resets. This allows you to “debounce” requests.
  • changed - Allows you to specify that a request should only be issued when the value property of the given element has changed.
  • throttle - Allows you to throttle events, only issuing them once every certain interval. This is different than delay in that the first event will trigger immediately, but any following events will not trigger until the throttle time period has elapsed.
  • from - A CSS selector that allows you to pick another element to listen for events on. We will see an example of this used later in the chapter.
  • target - A CSS selector that allows you to filter events to only those that occur directly on a given element. In the DOM, events “bubble” to their parent elements, so a click event on a button will also trigger a click event on a parent div, all the way up to the body element. Sometimes you want to specify an event directly on a given element, and this attribute allows you to do that.
  • consume - If this option is set to true, the triggering event will be cancelled and not propagate to parent elements.
  • queue - This option allows you to specify how events are queued in htmx. By default, when htmx receives a triggering event, it will issue a request and start an event queue. If the request is still in flight when another event is received, it will queue the event and, when the request finishes, trigger a new request. By default, it only keeps the last event it receives, but you can modify that behavior using this option: for example, you can set it to none and ignore all triggering events that occur during a request.