Htmx and the Rule of Least Power
blog.gypsydave5.com
blog.gypsydave5.com
Useful abstractions necessarily impose restrictions compared to a free-form 'all powerful' approach, but abstractions make it easier to perform/compose meaningful operations.
A compiler can reason about an AST far more easily than it can reason about a machine-code sequence, for instance. A compiler typically converts from AST to machine-code pretty late in the game, as you want to take advantage of the utility of the abstraction, not the unlimited power of directly working with instructions.
This doesn’t work for projects that are planned to live for years and we aren’t sure of the scope of it beyond the next few months.
You may feel you completed all the current features neatly with HTMX or whatever, but what happens when later your PM or designer asks your team to implement, say, a complex multi-step form with a bunch of frontend state and validations?
People downplaying the need for tools like React and Next.js don’t usually acknowledge that these tools are used to ensure long-term flexibility of your tech stack and to maximize the talent pool to draw engineers from. It doesn’t matter if your site is slightly less broken for the few people that turn JavaScript off in their browsers.
will we get a next.js framework to make it easier to use next.js to make it easier to use react to make it easier to use javascript in the near future?
please for the love of god stop enabling these people.
My counter-argument is that the simplest tool has the largest chance of not breaking over long periods of time. I have dynamic websites I built 10 years ago that still run almost untouched because I used the simplest stack possible.
Contrasting that, in the commercial software world we rebuild from the ground up in 1-5 years, and we aren't even building complex things. Same level of interaction, but a stack that has an enormous complexity and web of dependencies and moving targets that absolutely require a steady hand on the maintenance wheel. Your examplen scenario is not that scary, we have been building that kind of UX long before React and friends.
Your final comment about people who disable javascript is disappointing, but an opinion you likely share with many PMs. I would recommend a look into accessibility, and also try to see why people might advocate for graceful degradation.
https://tailwindcss.com/blog/standalone-cli
It's not as full featured, but it's pretty good frankly for what I do with it.
> My counter-argument is that the simplest tool has the largest chance of not breaking over long periods of time. I have dynamic websites I built 10 years ago that still run almost untouched because I used the simplest stack possible.
My whole argument was that any reasonable frontend stack can work if your requirements stay constant. But let’s say in a startup you definitely don’t know on day one what you’ll need to implement. So it’s understandable why people pick something that’s popular and capable.
The ”YAGNI” motto usually needs to be combined with ”don’t paint yourself into a corner”.
Lol, no. Postgres has tons of features that SQLite lacks.
nothing wrong with using htmx for the relatively dumber parts of your app then using something like preact or alpine when you need more reactive behavior
HTMX can handle this perfectly.
"Frontend state" in the context of a form is...the form. Add as many hidden fields as you need, and you've captured the state.
Validation - no problem. The "backend" can choose what response it sends, and to where in the page. Your form fails to validate? Annotate the failures in the markup, send back a fragment that replaces the fields that fail, all good.
It's also not an all-or-nothing proposition; you can have Javascript alongside HTMX. Add "hooks" into htmx.load(), and they'll be fired every time a new fragment comes back; I like to use querySelectorAll to look for elements marked up with whatever attributes are applicable, and then manipulate them in whatever way I need (e.g. to turn markup into pretty/interactive charts).
From people who have made the switch: any regrets? Any sharp edges? Can I still use all my Tailwind components without issue?
A pattern I've been using a lot is not changing the backend at all - each endpoint still returns the full page. Each hypermedia control makes liberal use of hx-select and hx-select-oob to update the elements that may have changed.
This isn't super efficient, but it provides some "locality of behavior" in that you can look at a hypermedia control and know what other elements might be changed by it. It also means the backend doesn't really need to "know" about HTMX.
Back in the day, with Java JSP, there was a tag library called DisplayTag, which handled tables. It did a similar thing for in place paging, albeit a bit more brute force.
All JSP pages are buffered as they’re rendered. When the tag was rendered in “Ajax” mode, at the start of the tag it simply flushed the buffer, thus eliminating anything generated before, and at the end it simply aborted the remainder of the page. This effectively just returned the entire table element in isolation from the rest of the page.
It was a clever mechanic at the time.
https://shoelace.style/components/option
but I did not find a wrapper for <optgroup>.
It works great, after you get used to how it expects things to work. Basically, think like every HTML element can be a little "form" which you can submit and replace its contents with the returned HTML.
In the server it's not hard to get it to work, I implemented it using Kotlin's KTor (but any server technology that lets you generate HTML would work).
I still needed a very minimal amount of JS to do some things that I found annoying to do with HTMX (e.g. in-page filtering), but once I accepted that's ok, it's been working very well.
I’m still using htmx, and enjoying it, just raising a concern as you asked.
once june rolls around i can dedicate a lot more time to htmx
good news is that most issues are fairly obscure: the htmx codebase isn't too complicated
i posted a walk through of the important parts of the code here:
https://www.youtube.com/watch?v=javGxN-h9VQ
2.0 (coming soon) works pretty much the same way
I can understand not wanting too big a dev team, as bloat and extra features is bad in many projects, but would really hurt htmx, when the aim is to be minimal.
I use Tailwind with out a problem, I don’t use components - assuming they are JSX components you’ll just need to investigate a server side way to turn that JSX component into html so that when the client receives it htmx can insert it into the dom and bind everything … I think?
Best bet is to head over to the htmx Discord as they are very helpful in there.
The thing I like the most is loading tabular data. With react you need to paginate way earlier than just a plain old html table, browsers are really fast at just displaying a tonne of html. If you do need to paginate then htmx supports infinite scroll with about 20 characters of code!
Basically there's stuff on my big computer, and it needs to get onto some other guys' small computers. Sometimes the small computers need just a little bit of stuff from the big computer, or they want to tell the big computer something. If you put HTMX on the small computers, they can talk to the big computer and ask for bits of stuff whenever they want. And my nice big computer can do all the thinking, and I can tell it how to think, and the small computers aren't expected to think much, they just do what the guys say mostly.
This is great, and to me much better than the alternative which is that in addition to having to make the big computer think straight, I also have to install fucking npm on my own computer so that for every single feature I can write a turing-complete piece of thinking sludge which then goes onto hundreds of the other guys' small computers and tries to think for itself and breaks. Now I've got a big computer thinking, a hundred small computers thinking, and all these dumb guys thinking too. And I'm trying to think about what they all might be thinking and how that all interacts, fucking nightmare.
HTMX means that only the big computer is going to do any serious thinking, and the small computer only has HTMX, so it's too dumb to think. And so when I am thinking about the computers, I don't have to imagine what two computers might be thinking - only one.
Did you know that if you want to run a program in the terminal on your own computer, in order to make programs for other guys small computers, you should say "npx" not "node"? Even though they both execute code? If you don't know this innately, a priori, unfortunately you are the programmer equivalent of a stray dog or sewer-dwelling rodent. Oh and did you know that it's important to learn "type script"? Ah yes just what a language (or languages) made out of warm toffee needs, homotopy type theory. It will be so awesome when my IDE can render a little intellisense hint thing of the compound "List of List of Errors" type I just invented and finally I won't need to understand what the computer is thinking but can still commit a shit load of formally self-consistent code to prod. Statements dreamed up by the utterly deranged.
Anyway HTMX is very good in my opinion. One pjs_ Top Tip is that you can write less code if you make your server-side endpoints either return the full template or a partial component depending on the whether the HX-Request HTTP header is present or not - saves writing two different endpoints for the full page vs partials.
Don't let the new-born AI sentience hear this, them's fighting words.
But it does illustrate the kind of power that JavaScript gives. The language and especially its ecosystem is a jungle of abstractions and complications, hard to control and easy to break. That includes React and Next.js, speaking as someone who is still deep in that world.
> put HTMX on the small computers, they can talk to the big computer and ask for bits of stuff whenever they want. And my nice big computer can do all the thinking
That's a nice way to describe it. HTMX is re-thinking the problem space from the ground up, starting with HTML. That's a lot simpler to reason about, directly working with the user interface as it is rendered in the browser. How that HTML is dynamically generated is left up to the server, the actual "thinking" part.
> "type script"? Ah yes just what a language..made out of warm toffee needs, homotopy type theory
TypeScript is brilliant though, it's the best thing that could have happened to JavaScript. For what it had to work with as a starting point, it builds on that foundation a language that's more sane and reliable. With a type system that's at least better than before - implicit/invisible types or none at all. And the language server that enables intellisense, it's an ingenious way to empower the code editor - I use it heavily and can't imagine programming without it now.
> make your server-side endpoints either return the full template or a partial component depending on the whether the HX-Request HTTP header is present
Good to know! I'm still learning how to use HTMX, especially on the server side. It's a different way of thinking than an API with JSON.
This is great, just remember to add "Vary: HX-Request" header to your response else risk confusing the browser's cache.
You can even send custom headers along with the request (important for 'Authorization' headers) You can also trigger behavior after the fetch by sending an 'HX-Trigger'. So on the surface, does seem your one-stop shop for all things client-server interaction.
There may come a point howecer, where you hit a brick wall with HTMX. Frameworks were created for a reason, and it wassn't just the fact that fetch() and setting innerHTML were too verbose (those can be easily abstracted away)
Then you're back in framework land. And can be hard to make those two place nice with each other. React, particularly, doesn't like you messing around with innerHTML.
It's far better to use something that at least embeds the templates in the web page with some simple js to show it (eg alpinejs) and a simple, private API.
I was never a JS fanboy but the modern JS/TS frameworks that let you organize and test the UI without an entire system running is better for maintenance imho.
It’s a non-point.
Do you think we have a bunch of HTML files spread out everywhere, and that we aren’t generating all of those endpoints automatically? We don’t even write 95% of the endpoints with HTMX. They’re generated from the ORM class.
It was amusing when I heard about RSC, since we’d basically been doing that for years at that point, except in whatever language the backend team is already well versed in.
If I need to add one boolean variable to a page, in React/Vue land I need to update 7 files and create a mutator and a fetcher and an actor and a dispatcher.
In HTMX land that one added variable requires editing, one file…
State was just an illustrative example that “writing a thin HTMX layer” is not necessarily a bigger lift than “just use a framework”.
There’s a big gap between “write some small thing in PHP” or whatever your team knows, and “learn React well enough to do it the right way”.
As the person I replied to said, it’s not about what’s possible. It’s about getting something done today.
We don’t write 95% of the endpoints. They’re auto generated.
And this may be a shocking idea to you, but when we do need to build a custom endpoint, we still build it as a component (just like you would in React).
This means you have a single template per page and only need to split out partials for things that are actually shared, rather than for every action on a single page.
Why do you think the client side requires fewer partials, if you use the same scope of data changes?
I think it's perfectly sensible to have a general-purpose programming language in the frontend.
Of course, when ingy and I worked together on https://p3rl.org/JSONY to provide something more config-file-like for systems configuration, the developers at the shop that I first got an after action report from ... went "ooh! this is so much simpler than YAML!" ... and promptly invented turing complete JSONY.
My next attempt at a configuration system is going to be turing complete out of the box so I can actually design it for that.
>Web resources that use these technologies [of least power] are more likely to be reused in flexible ways than those expressed in more powerful languages.
>The reason for this is that the less powerful the language, the more you can do with the data stored in that language. If you write it in a simple declarative from, anyone can write a program to analyze it in many ways.
Seems unclear how we jumped from ideas of information reuse to 'HTMX is better than smelly JS' when information reuse, as pitched by TBL, is miles down the list when evaluating tech.
So, not to rain on the HTMX parade because it's obviously the latest thing web devs are getting tattooed, but invoking Principal of Least Power here seems.. awkward/hamfisted.
Is a lighter client and heavier server a good thing? Not always… look at Web3 for example, where many apps can be written against a blockchain and no server at all.
React: I don’t think about you at all
Where the application is doing lots of micro-level stuff, like maybe you are drawing on a canvas and occasionally sending a payload of updates to a server, I think then HTMX would be much slower and clunkier, and that is when you dust off your React.
All HTMX is doing is fetching HTML snippets from the backend and patching them onto the DOM.
That's how it should work, although you can get easily get around that and tack on client side rendering.
On the other side of the scale, React has overheads like a virtual dom.
It is a complicated question as to what is most performant, who bares that cost, and so on.
The issue is overhead and complexity for the developer, and maybe, server costs.
React comes out ahead in server costs, since doing work on the client is very cheap (provided there isn't a performance issue that turns users off, which there isn't).
And in terms of dev time, it depends, but you can't say "look, with HTMX you can avoid code" because you still do need to write code, but now it's in the server.
Those were the days... now you need a bible on CSS.
It’s a return to the old easy times.
However, many times I only use a small subset of it.
I recommend to begin with small steps and increasing the complexity a little bit on each one before being crazy applying ALL for a “to-do” app: pure html, htmz (a tricky way, TAKE A LOOK), htmx and react or whatever.
Finally, I also recommend to follow htmx in Twitter, you will laugh a lot.
The angularJS experience was so bad, not just because SPA’s were terrible but coding in JS/npm was a horrible ecosystem… I had a much much better time doing simple UI’s in Rails/HAML/jQuery than anything else. Server side rendering was so much simpler than any time I tried to even look at doing anything in react.
Would I like HTMX? What are the best practices around server side rendering? Have folks had good experience with Rust server-side code emitting HTMX pages? Any decent frameworks for this that are as opinionated/useful as Rails was for me?
It can get unwieldy if the app requires complex state management. While you can (somehwat hackishly) return JSON, its not really what its for.
Its kind of a throwback to the days of PHP, except without the page refreshes.
The actually difficult problem is hardly being addressed though, namely globally distributed data stores, especially with distributed writes. That's the hard problem, I haven't really seen a very convincing solution yet for normal 'web-apps'
Only showing not a single piece of logic more complex than a simple alert. Heck! This looks like a dirty hack, and for some reason it exists, giving htmx the power of the javascript, but now all inside HTML of course. How come it's applying the rule of least power if such thing exists? 36 new custom attributes for HTML, _most_ of what you want should be covered, maybe one day you will want something else, and we will cover it with more custom HTML attributes, until we reach hundred of them for every use case. No javascript needed. And yes, React unlike HTMX is not a framework, it is just a library for building user interfaces, it does not provide a specific structure for developing your application, it is just a tool to perform a specific task: building a view layer of your application.
https://htmx.org/essays/a-real-world-react-to-htmx-port/
the hx-on attributes are to deal with the fact that HTML's native on* attributes don't allow you to capture custom events, they aren't a focus of the library
the core idea is hypermedia, we have a book on the idea here:
You can learn htmx in a day, and it's just another tool in your toolbelt.
Or don't, doesn't really matter.
And what is HTMX? A 44KB-minified JavaScript library! So this statement is false. If you really want to be lightweight, use pure CSS frameworks like Picnic (https://picnicss.com) or Spectre (https://github.com/niutech/spectre) and pure HTML out-of-order streaming (https://github.com/niutech/phooos). If you really want a sparkle of JS, use 166b (bytes, not kilobytes!) HTMZ (https://leanrada.com/htmz/).
I assume the compiler can give warnings at compile time?
You can still do JS on the client here and there, but that becomes much less needed.
...instead write it in htmx, and html partials server-side using a templating library. What could possibly be wrong with splitting up the presentation logic and spreading it throughout the backend instead of just writing a little bit of javascript?
One code base rather than two?
Simple pages become simple again?
AJAX philosophy was based around client side render - Asynchronous Javascript And XML. XML was JSON before JSON.
jQuery is/was just a fetching library. The modern fetch() API as well as Promises/async/await made it largely obsolete, although some people still swear by it (they just released a new version actually). You can fetch raw HTML and dump it into innerHTML, but thats not how most people use it. They would do client-side render based on the XML (later JSON) returned.
People keep genuinely saying it's a good thing to have many tools to apply to the right usage. Personnaly, constantly switching from htmx to vue.js just fucks my brain.
I miss the time where I used Django or Rails and didn't need to ask myself all these questions.
computers are fast
Yeah, why not. But consider this: JavaScript exists because the axiom does not hold for the web. Or rather, a programming language is the least power you need for a general platform such as the web.
If you're unfamiliar with the name you might be well served to look up his contributions to the web first.
Is HTML+CSS+JS more powerful than React? Is Excel more powerful than C? One could argue either way.
The better rule is, perhaps, apply KISS to your architecture choice.
If I can reduce 100 lines of HTMX into 10 in React, I'd choose React. Because KISS. But according to the least powerful principle, and the author's claim that HTMX is less powerful, I should choose HTMX. Nah...
carry on
Because that sounds like complexity and has nothing to do with the rule of the least power?
But I don't see that using htmx instead of react gives you any such guarantees.
However a a developer or team, if you say "this page only includes the HTMX library and no other scripts" (something that is easy to verify) then you know a lot about what can and can't happen.
In a sense HTMX is a framework that provides a non-turing complete DSL with limited interactions.
Whereas React alone provides... well nothing, because it isn't a framework. You need JS to initiate it, and do anything with it at all! So a React app by extension must have a lot (or maybe a little, rarely) custom Turing-complete code with access to the entire operating system that is the Web API!
(I appreciate that people's definition of Framework vs. Library will differ, but the main point stands that React requires a decent chunk of turing complete code to do anything useful, whereas HTMX requires no turing complete code on the client but just markup.)