I work mainly on the back end but do need to do front end stuff from time to time. Having had my eye on Htmx for quite a while, and having recently gone through a painfully breaking NextJS update, I’m seriously considering going all in on it.
From people who have made the switch: any regrets? Any sharp edges? Can I still use all my Tailwind components without issue?
I've used HTMX quite frequently recently for internal frontends (admin pages, reporting, etc.). It's quite good.
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.
Nice way to incrementally add capabilities to an existing app.
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.
I toyed around with it, but ended up using server-side rendered interactive Blazor. That’s pretty much the same concept as HTMX, but has a larger ecosystem and more flexibility in some ways.
HTMX gets all the hype right now, but there are other tools in the same vein, my favorite being Unpoly (https://unpoly.com). Together with Shoelace (https://shoelace.style) you get nice GUIs real fast, without the burden of complicated dependency management and build steps. Also, you don't have to write a lot of JS, just what is needed for small enhancements, as it was meant to be. Some might say the main drawback is the tight coupling to your backend. In my case, this is also the main benefit as it integrates perfectly with the backend framework (Django).
I've used HTMX to create an internal app for us to manage Pull Requests from multiple repositories in a single page.
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.
One thing which worries me is GitHub issues (including mine, it’s just a doc issue) don’t seem to be getting much feedback, not sure how big the dev team is.
I’m still using htmx, and enjoying it, just raising a concern as you asked.
early spring is always the worst time for me because i'm in the thick of a hard semester (in spring i teach compilers), i'm helping getting youth baseball rolling, i have to get taxes worked out, etc.
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:
I understand those exact issues, I'm also an academic, and sometimes the github issues and PRs on my projects build up -- and nothing I've released is near the popularity of htmx!
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 it for our internal app that staff use and it’s brilliant. The sharp edge is probably getting your head back round server side rendering if you’ve been in SPA land for a long time.
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!
We use it for a fairly chaotic internal CRUD tool together with Flask and Postgres.
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.
I played with HTMX for a bit. Its pretty cool and basically an easy way abstract away fetch() and swapping innerHTML.
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.
Anyone using Django with HTMX? How are you writing UI tests for HTMX behaviour? The standard Django tests don't run JavaScript so what do you use for this and how is the performance?
That's the fun part. It's just HTML attributes, so you can test them without a full browser and JS engine. Just parse the HTML. Tests are super fast and never flaky.
But how are you checking that e.g. on submit the HTMX replaced the correct selector inside another form and that on submitting that form HTMX uses a HX-Redirect header to send you to the right page? If you're not testing that, don't you get cases of tests passing when the UI is actually broken in the browser?
Just submit a request, capture the response, and test it for whatever you like. Django has a test HTTP client that lets you craft whatever request you like, submit it, and captures the response. Once you have the response it's trivial to check its HTML content and its headers.
We did this 20 years ago and you just end up with piles of unmaintainable partials all just used for a single page.
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.
Not OP but: spreading a UI amongst a bunch of files, which themselves have server side templating and logic in them and can't be run, imported, or tested in isolation.
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.
No it's a point because the number of endpoints and partials explodes to support every action in the page that uses the "get HTML and replace it" pattern.
Cant you type your partials in some way? I think for complicated things with htmx you need to write a thin layer to manage this explosion of templates.
It's more just the fact that a single page gets unnecessarily split across multiple files (where there's no reuse with other pages). It makes refactoring difficult and slows development IME.
How is this different from React? Every page in the app is made up of components from numerous other files.
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.
Isn’t that just pushing the complexity somewhere else? The selling point of HTMX is that it’s simple because you don’t need to deal with frameworks or JS, just write HTML! But if you have to start adding layers to support it then all that’s happening is the complexity is being moved out of the framework and into your code. Stone soup development…
I get what you mean, but for me the target is not deciding if htmx is up to x standard, but getting things done. Writing a thin layer as described above solves these issues for me.
Yes. Writing a thin layer is a minor task, compared to say, introducing a client-side store and trying to manage all of the complexity of state synchronization.
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…
I don’t understand what HTMX has to do with state synchronization. If you want to implement a thin client authoritative server architecture in React (or another JS framework), you can just do it that way. React doesn’t have any opinion on how information flows between client and server. State in React is optional, you can do everything with props if you want to.
Also, when your front-end html changes, any number of these partials might have to change. Versus just returning data (json) and letting the front-end render what it needs from it. The latter seems like an obvious ideal compared to the former.
If you assume the people building the backend are incompetent, then I guess you have a point?
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).
Because instead of needing separate partials for your inline edit template and all the other actions, you just stuff them into the page as hidden divs.
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.
Sorry, I don't get it. If you have client side rendering, you need a template for every thing you want to replace, at whatever level you choose (from full page to single element). If you do htmx, you do the same - provide a template for each replaceable part (from full page to single element). In each case, it's your choice how granular you want the updates to be - it can be one per action, or just rerendering the whole page.
Why do you think the client side requires fewer partials, if you use the same scope of data changes?
With HTMX you shouldn't have a "template" per action. Most actions work on some "entity", and the "entity"'s page should be returned by the action, as it's very common for an action that change one bit of the "entity" to affect more than one part of the "entity" rendering. So you don't need one template per action, you need one template per entity, and different actions may replace the same entity. This is almost exactly what you would do in React, with "entities" being "components". I've designed a HTMX app this way and actually called the "templates" components. Each component is either a function or an actual (Kotlin) class with a render method. I can test the components in isolation, just like you can with JS frameworks, but all code is on the server - despite the app itself feeling just as reactive as any JS framework-based app.
For the Python/Jinja world, there is Jinja2-fragments that allows you to return blocks of the template without having to extract it to partials. I am sure there are similar solutions for other template languages. See https://github.com/sponsfreixes/jinja2-fragments.
With JQuery you're still writing JS to do everything.
With HTMX, you write almost no JS. You write HTML which contains some directives like "hx-post='/clicked'" which will make a POST request to the `/clicked` URL path, similar to how HTML forms already work... and then you write the logic to generate more HTML in the server. That is: the server becomes responsible for the logic, not the client.
You can still do JS on the client here and there, but that becomes much less needed.
> With JQuery you're still writing JS to do everything. With HTMX, you write almost no JS.
...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?
> With jQuery and AJAX you're still sending HTML fragments just like with HTMX.
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.
In my case, I already write a considerable amount of presentation logic in my the Django side of my project, merely because of Django's templating language limitations (which is okay, I prefer writing it in a sane language instead of wrangling esoteric features of DTL to get what I want). So adding a view function for an HTMX endpoint isn't really "spreading it around the backend" if your workflow is similar to what I described.
> suggests choosing the least powerful [computer] language suitable for a given purpose
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.
Are you recommending Next.js for its longevity? My experience over the last 18 months is that every new version introduces breaking changes. I wouldn’t want to come back to a Next.js project in 5 years and have to deal with migrating to Node.js v32 and whatever Next.js has broken in the meantime.
Don’t get me wrong, I’m not a Next.js fan either. Could’ve widened my list of examples to any SPA libraries and server-side JS frameworks. I just wanted to highlight the issue with the analogy: unlike some criminal a police officer is using force against, the nature of issues to be tackled in most software projects will keep changing.
that is going to be your experience no matter what you use if you want some horrible bloated frontend framework, or in this case, a horrible bloated framework for a horrible bloated front end framework.
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.
Long term flexibility is a very surprising way to describe a JS stack. They are easy to build in, but there is nothing robust about the ecosystem. When in 5 years a PM asks me to add that simple multi step form, I'll probably have to tell them it's blocked by replacing deprecated dependcies and our validation library doesn't support our new element types so we need to rewrite all the validation across the site to use a new library... man I feel a burnout coming on.
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.
When trying HTMX, I decided to use Tailwind for layout. Tailwind requires npm and Node to work. It was my first experience with Node. I already had some Node version installed on my machine. Running Tailwind gave some vague "Unexpected token ?" error and nothing else. After I bumped Node's version, it worked. Sure not using the latest versions of the tools is a bad idea, but the fact is, something from the JS ecosystem was basically the only thing in my stack which broke immediately (with a vague error, nothing like "hey, old version of Node!")
There are painpoints in working with ”modern web stuff”. But:
> 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.
Oh for sure, and in a commercial setting your other point about being able to hire people is just as important. Don't get me wrong, React and friends are totally fine tool choices for teams and projects of significant (or loosely defined) scope.
You're going to definitely need a schema, so you want a SQL database, which leaves SQLite and Postgres. The only difference between the two is one requires a server. If that's too inconvenient, SQLite is a solid choice.
Regardless of the context, your statement that the only difference between SQLite and Postgres is that one requires a server is plain wrong. That would be like discussing Emacs being more complex than Vim, and then saying, "The only difference that Emacs has from Vim is that Emacs typically uses a client/server architecture".
yagni: you add a library to help with that more complicated feature when you need it
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
> a complex multi-step form with a bunch of frontend state and validations?
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).
To use his own "butter knife / cheese knife / lightsabre" example, it's like if I want to butter some toast, I should choose the butter knife, right? Oh but now I want to cut that melon and the butter knife is the only knife I have because I chose the least versatile/powerful knife because they told me to.
There does seem to be a little sleight of hand going on, since much of the work that you do in react is rendering, and with HTMX you’re just shifting that to the server.
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.
A HTMX-y app will typically be a fetch-heavy app. Think TODO list, where each time you add a todo, you want that persisted on the server anyway. Yes you are sending more down the wire. I doubt rendering a partial HTML template is that much more work than formatting JSON but there is more crap to send down the line for sure.
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.
Render is a different thing in both places. Server Renders is ... formatting a sequence of bytes. Hopefully your templating engine is optimized and it is a low cost operation. Rendering on the client is obviously more involved as it requires actual rendering on the screen using the graphics drivers.
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.
I'm not talking about most performant. Neither HTMX nor React has a performance issue.
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.
Server rendered content has had 25+ years of development and the approaches and constraints are well understood. Client-side rendering has arguably had less than 10 years of development and the approaches and constraints are still fragmented and poorly understood. The maturity and simplicity of server side rendering shouldn't be underestimated.
I was writing SPAs with jQuery in 2008. By then they were already well-established. We used UI component libraries (mostly custom) on frontend and AJAX for server updates in XML/JSON format. They were hard to build compared to today, but "less than 10 years" of SPA development is simply incorrect.
sooo much effort is going into saving a few milliseconds either by rendering code in the browser or on the server - honestly who actually cares.. I like react because of JSX which I prefer to just normal HTML, but whether that's rendered in the browser, or on the server, also ok to ditch the whole thing and replace it with templating.
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'
But it only seems to make sense to me if you actually get any extra guarantees from it. HTML+CSS without JavaScript gives users a nice guarantee that the content you see is what you get. No extra delays waiting for data. No mutations at a later time. Etc.
But I don't see that using htmx instead of react gives you any such guarantees.
That is right, so from a security perspective, as an end user, you can't "Disable JS, but enable HTMX only".
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.)
The founder of HTMX said many times that he hopes the ideas behind it evolve into web standard, such that you wouldn't need JS anymore. I think HTMX is a great showcase for how far "any element can send HTTP requests" can take you.
These years I tried many approaches and I felt in love with htmx for my side projects.
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.
This reminds me of a great talk, Constraints Liberate, Liberties Constrain, by Runar Bjarnason. [0]
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.
Genuine question, anyone knows the "bootup" time when you load a page? I imagine htmx "engine" needs to find all the elements on the page with hx- prefix. Is this fast?
yeah, query selectors are pretty fast, we've had a few complaints on really large pages w/ huge tables (20k rows) and lots of elements with htmx attributes on them, but on most sane pages it isn't noticable
Somebody made up a "Rule of Least Power", which is taken as some sort of axiom, and then this article gets going from there without questioning the axiom further.
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.
I know the name. I am not impressed by his reasoning. I mean, HTML and CSS being the result of the rule of least power? CSS is a mess, and there is nothing least about it.
I have no idea what CSS 1.0 looked like, but I suspect it was an entirely different world when he made that statement. At that time, the web was really just blobs of text with the most minimal formatting. Not the basis for trillion dollar companies that want pixel perfect alignment.
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.
used it on small side projects which worked well,but I am concerned it could lead spaghetti code for larger projects,for that reason I now stick with vuejs
I thought they were gonna make some argument about least power in the frontend backend dynamic. But then they are like "why are we not using all these programming languages equally?".
Because that sounds like complexity and has nothing to do with the rule of the least power?
A dev myself, I see any new tech that looks like something I've seen before, but different from the immediately previous, as the natural young revolt against the old (5 years older), in an attempt to be important (i.e., e.g. being paid). Sometimes I'm younger than last year too, and I throw away a lot of what I learned. I should strive for wisdom: knowing what should come and what should go.
154 comments
[ 4.7 ms ] story [ 185 ms ] threadFrom 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 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.
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).
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.
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'
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.)
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.
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.
[0] https://www.youtube.com/watch?v=GqmsQeSzMdw
Those were the days... now you need a bible on CSS.
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.
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.
Because that sounds like complexity and has nothing to do with the rule of the least power?