After moving my blog over to HTMX 4, I was excited to learn that HTMX now supports the findAll operation in its CSS selector attributes (such as hx-disable). In earlier versions of HTMX, the find operation scoped the subsequent CSS selector to the host element of the given attribute. Which was helpful; but it could only match a single element. The findAll operation works the same way — scoping the subsequent CSS selector to the host element — but it allows you to match on multiple elements. Which is exactly what I need when submitting forms with HTMX.
When you focus a form field and hit the Enter key, the browser handles the submission by finding the first submit button within the form hierarchy and using that button as the "submitter". If your form contains multiple submit buttons, this can lead to unexpected behaviors; especially if any of those submit buttons have a name attribute. Which is why I often include a visually hidden submit button at the top of my forms to act as the "unnamed submission sink".
Which means that my forms often have multiple submit buttons. Which, in turn, means that an attempt to disable submit buttons in HTMX 2.x with find:
hx-disabled-elt="find button"
... would end up disabling my visually hidden submit button and leave my rendered submit button(s) fully functional.
I could work around this limitation in HTMX 2.x by giving my form an id attribute; and then scoping my CSS selector to the form's ID:
id="myForm" hx-disabled-elt="#myForm button"
But with findAll, this level of jank is no longer needed. I can simply scope my button selector to the host element:
hx-disable="findAll button"
Note: The
hx-disabled-eltattribute in HTMX 2.x is now thehx-disableattribute in HTMX 4.x. Also note that the documentation onhx-disabledoes not demonstrate thefindAlloperator, only thefindoperator.
To demonstrate, here's a simple ColdFusion form that's using HTMX 4 to POST back to itself and then sleep() for 2 seconds. The sleep() is here to make the disabled attribute styling on the buttons evident.
<cfscript>
// Simulate slow CFML processing (as if) to see disabled buttons in action.
if ( cgi.request_method == "POST" ) {
sleep( 2000 );
}
</cfscript>
<cfoutput>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>
HTMX 4 Adds findAll Support In CSS Selector Attributes
</h1>
<!---
See [hx-disable] attribute - we're disabling all buttons (within the form),
when the form is submitted via HTMX.
--->
<form method="post" action="./index.cfm"
hx-boost="true"
hx-push-url="false"
hx-target="this"
hx-select="form"
hx-swap="outerHTML"
hx-disable="findAll button">
<p>
Rendered: <mark>#now().timeFormat( "mm:ss" )#</mark>
</p>
<!---
Since these are INSIDE the boosted form, they will be matched by the host-
scoped `findAll` selector for buttons (inside the hx-disable attribute).
--->
<button type="submit"> Inside Form </button>
<button type="submit"> Inside Form </button>
</form>
<p>
<!---
Since these are OUTSIDE the boosted form, they won't be matched by the
host-scoped `findAll` selector for buttons (inside the hx-disable attr).
--->
<button type="button"> Outside Form </button>
<button type="button"> Outside Form </button>
</p>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/htmx.org@4.0.0/dist/htmx.min.js"
crossorigin="anonymous">
</script>
</body>
</html>
</cfoutput>
This demo has two sets of buttons - those inside the form and those outside the form. The latter set is there to prove that findAll is scoped to the form and is not selecting all buttons on the page:
As you can see, the two submit buttons inside the form are disabled while the form is processing; and the two buttons outside the form are left in tact. Admittedly, this is rather niche; but I'm excited to see findAll support land in HTMX 4.
Reader Comments
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →