imo any experienced frontend framework person will be able to pick out the issues with this impl. OP is returning entire strings of HTML (App, Todo, Icon) to rerender on state changes. this works when 1) you dont care about keeping UI state on the parts that are replaced (incl any stateful children of the UI element that happen to be there in your DOM structure), and 2) when you dont have to update the app in any other places when your state changes. go ahead and build your whole app by replacing innerHtml, frontend frameworks will be right here when you get back from speedrunning the last 10 years.
in other words, this todo app is just about the most complex of a frontend you can easily* build with htmx, i'm afraid. try to fix either 1 or 2 and you end up building components and your own little framework.
as an exercise to demonstrate, try taking OPs code and adding a count of todos on each All/Active/Completed tab that should update every time u add/edit/delete the todos. see how much extra ui code that takes. compare with equivalent [framework of choice] impl (in most it will just involve 1 state update, thats it). this is htmx's explosion of complexity that makes it not [ optimized for change ] (https://overreacted.io/optimized-for-change/). code that is hard to change eventually calcifies and consumes code that is easy to change if you do not consistently garbage collect (nobody does)
i bought the hype too until i tried building something nontrivial in htmx and im afraid the aforementioned islands of interactivity you can build are very very smol islands indeed.
happy to revisit my opinion if there are componentlike design patterns in htmx i am not aware of.
*emphasis on easily; with enough elbow grease u can do anything ofc. but then you fall out of htmx's very narrow [ pit of success ](obligatory codinghorror dot com link)
In my decades of experience building web applications, I have found it exceedingly rare for components to benefit from SPA-style state management. These frameworks build layers of abstractions to replace functionality that exists in the browser. For example, web forms should never require the level of complexity that frameworks like React steer developers towards: downloading JS components, listening to events to build a local state, crafting an AJAX request, rendering the return JSON as HTML. It almost seems as though there is an entire generation of frontend developers who never learned that there are way simpler alternatives that perform just as well in the real world. htmx might not end up being a SPA-killer, but progressive enhancement has always been a worthy contender.
> abstractions to replace functionality that exists in the browser.
I was just having the conversation yesterday. We were talking about how React Query/Tanstack Query is a bit of a rats nest under the hood. We're looking into ways of taking it out to simplify things a bit, especially since we aren't using a ton of the library's features, nor will ever have a need for them. Found myself saying "I wish the native fetch() had a built in cache layer... oh yeah".
The "standard browser" is pretty much the most expansive standard library that exists.
To me the part that rubs the worst, is that _after_ downloading JS components, listening to events to build a local state, crafting the AJAX request, and rendering the return JSON as HTML, the SPA will then change the URL in the URL bar so that users can (hopefully) bookmark the monstrosity. This is after 75% of the page has been re-rendered anyway. And just to echo your point, there's an entire generation of frontend developers who think this is normal.
It's more like the other way around. Veteran web devs are stockholm-syndromed into thinking the web should always work how it used to work, they tend to think about the web as some sort of sacred internet document. Most devs these days view it as just another medium for apps, and if you look at the web from the app developer point of view, this is completely normal. Is it broken in many ways, absolutely? But not because it's not now the web used to work, as it was also broken/insufficient for modern needs.
There is an entire other discussion about how to keep the web as "information superhighway" (as opposed to an app medium) and accessible. I am sympathetic to that cause, but I think we should create new web standards for that. As it stands, the html/css/js trio is doing too many things and sucks at all of them.
I don't know about the kind of web apps you've been building, but most of the ones I've built over the last 10-15 years have had too much interactivity to be done with simpler server side rendering.
Everything from MPAs, to SPAs, to animation heavy websites that could only dream on being tailwind. Progressive enhancement doesn't mean giving up on frontend validation, dynamic functionality, and juice. I'm curious what problems you haven't been able to solve without converting whole applications to JSX.
My idea of a complicated UI challenge is not updating DOM in two trees. I have found React to be inadequate for the hardest UI challenges that I've been presented with. Things like DOM manipulation for interactive animations should not be handled by React state updates.
I think the SPA and the no-JS SSR people get it wrong by making it so black and white. By choosing to use something like React, you've made everything only SPA. With SSR, you can at least choose to progressively enhance the interactions. Look at amazon.com. They have plenty of full page reloads, yet their site also has tons of interactivity. Just make sure that the thing you require a full page reload for happens at a natural transition where it isn't interrupting the user's experience.
That's the exact opposite of my experience. Completely boring biz software that was, in essence, collections of forms. Didn't need the additional development burden of an extra JavaScript codebase, but that's what's in vogue, so ¯\_(ツ)_/¯
I notice you started by a blanket statment and use a strawman that is forms in React, a framework known for being the worst for forms (if you don't know the right library). Overall a poor criticism of SPA as a whole.
Having an opinion on best framework and libraries does not make what I'm saying straw man. React is by far the most popular framework for building SPAs and from what I've seen everyone uses a similar-enough state pattern to what has been described. I would love to hear your recommendations though.
> when you dont have to update the app in any other places when your state change
You can replace elements outside of your direct tree if you want. The simplest case you replace the whole page and pick what elements you actually want to change.
You're thinking about HTMX wrong. It's for progressive enhancement, the default is a full page reload and then you progressively enhance parts of the HTML. You should be using the same code paths and template to generate the islands of interactivity as you do for the whole page. You can then optionally send less HTML by just sending the parts that you expect to have actually changed, your "islands".
appreciate that. ive been given the progressive enhancement spiel a few times. its obviously a judgement call that will be the right call for some people. but i think many people underestimate how requirements grow over time because our UI standards have gone up over time, even for basic sites that you dont traditionally think of as SPAs. data drives everything, you want your UI to be a function of data.
for the other stuff, the growing browser stdlib has basically replaced most of jquery's usecases. so (in the most non condescending or negative way possible) htmx occupies a very awkward sliver between "The Platform" and Frameworkland and after giving it some time I have yet to see the benefit from keeping any of it in my head
I'm obviously in the minority, but I breathe a sigh of relief every time I encounter a website that works workout JS, don't hijack basic browser functionality, don't make dozens of AJAX requests in the background, and overall just focuses on presenting the data I want.
Every time web sites reimplement basic browser behavior, which they invariably do these days, they get worse, often significantly, because they never get it right.
> i think many people underestimate how requirements grow over time because our UI standards have gone up over time
I think you are overestimating how much 'UI standards' have gone up over time, actually. Nobody except for a small 'extremely online' set of people and control-freak designers care about all those complex UI/UX requirements. Users certainly don't care. They want fast-loading, responsive pages that get out of the way and don't drain their batteries or clog up their connection.
The other thing here is that approximately no one can actually tackle the complexity introduced by SPA frameworks and 'UI standards', and it's far more likely that they bungle it up and make giant, wasteful, UX pitfall-ridden apps. With server rendered pages, plain old HTML, and progressive enhancement, we at least have a better chance of producing something usable.
If you render HTML on the client you still have to render a transport format (usually JSON) on the server side. Sending HTML just lets you skip the transport format and the client side rendering.
And letting your framework do the bookkeeping for you lets you skip the whole issue. I don't know the exact specification of React Server Component Payload, but I know that it somehow changes stuff on the client-side when the client interacts with the server. (It sends something like `["$","p",null,{"children":["a child","another child"]}]`)
It's still one server side template, you just render different parts depending on what is calling it. By default render a full page, if you want to get precious about a few dozen KB from sending a full page over the wire you can toggle some blocks off.
> 1) you dont care about keeping UI state on the parts that are replaced (incl any stateful children of the UI element that happen to be there in your DOM structure), and 2) when you dont have to update the app in any other places when your state changes
Htmx does have tools for both of these cases. Out of the box, htmx throws out state, but there are plugins such as morphdom-swap for merging in the new DOM fragment into the old while keeping state. I have some client-only state that holds references to DOM elements in Javascript, and by default, yes, htmx breaks all those references as those elements no longer exist. Link in morphdom-swap, and my references live on across reloads, even across attribute and content changes.
And for #2, htmx also allows you to swap in elements that are not the target element, just by specifying that that's what you want.
IMO these are pretty basic tools of htmx. Like you said, without them about the most complex thing you can create is a to-do list, and sometimes not even that.
Parts of htmx were yoinked out of the core library into an extensions repo relatively recently, as part of htmx 2.0. That might explain the relatively lower number of stars. More important than github stars is that it is indeed part of the htmx project and is documented here https://htmx.org/extensions/
Just step back for a second and think about programming without modeling the states. Framework or not, no amount of hacking/tooling can help you with that.
I'm not super-stoked about the idea of building SPAs on top of htmx, but what I have found works incredibly well is to build a traditional MPA (SSR etc), embed islands of interactivity where needed, and where something fancier is really necessary, embed a React or Svelte app into just that one portion of a single page.
yea im not even talking about SPAs in my post, just the complexity explosion that comes with updating state in more than 1 place / preserving ui state in the place that gets rerendered. it blows up in your face quickly if you have even any requirement volatility (https://stackoverflow.blog/2020/02/20/requirements-volatilit...)
I agree that it becomes complex if you have state on the frontend. htmx scales better if you keep all or most of your state on the backend. I've found that using the websockets extension really helps with automatically keeping the frontend in sync.
> I've found that using the websockets extension really helps with automatically keeping the frontend in sync.
I choked reading this imagining people thinking they're doing something simple (as in not complex) by introducing websockets so they can keep state in their Go backend and sync it with their front-end, ya know, to keep track of the # of TODOs checked.
But it is simple :) The underlying technology might be more complex, but the library is solid, it's trivial to update any part of the page once you have the libraries set up, and you don't need to write any javascript. Works for me!
I think you may mean easy. It may be _easy_, but it's not simple. There are so many more moving pieces, failure modes, operational issues now to consider. Websocket connections aren't free.
I guess I just have to disagree. My experience is that it is robust, and removes an entire category of problems that appear when your state is spread across the back- and frontend.
As someone else mentioned, SSE is a somewhat simpler protocol that achieves the same purpose. Same idea though.
If you mean SSE, then yes that would work just as well (unless you need the bidirectionality for the client to modify some aspect of the connection after the page has loaded). There is an htmx-sse extension too.
I'm not sure how XHR alone would let you automatically get backend state changes reflected to the frontend. You can poll one or more endpoint, but that's more complicated to get right and less efficient.
there's nothing to sync, the state is only in the backend. if you tell the user that the TODO is checked and you're only keeping track of it in the frontend and you don't sync it to the server and it's lost in the meantime, your UI lied to the user when they checked it and it showed as checked. With state on the backend, the user doesn't see that their data is saved until, you know, it actually is. And if all the state is rendered from the backend it can't get out of sync with the display
I hate it when a UI tells me I did an action when really there's an asynchronous background task happening that may fail
htmx can work well for a reasonably large class of web applications. not all, and certainly not all UI patterns, but w/a bit of a mind shift to the hypermedia approach & a bit of accepting some limitations thereof you can simplify a lot of things pretty significantly.
if you try to shoehorn it in to the SPA mindset, triggering server requests on every interaction, yeah, it's not gonna be great
Glad to see you here swyx. I think the issue you outlined is acknowledged by the htmx's authors and addressed in the Morph Swaps documentation: https://htmx.org/docs/#morphing
What is ironic though, is that the morphing algorithms are similar to what modern SPA frameworks do, except that it can be addressed without introducing new concepts such as vdom, zones, signal etc.
I agree that the island architecture is limiting when it comes to large scale application with state shared across multiple areas in the UI. I'd be curious to hear others finding success in building apps.
> frontend frameworks will be right here when you get back from speedrunning the last 10 years
More like speedrunning the period between 20 years ago and 10 years ago! React is 11 years old, much older than jQuery was when React was initially released.
thanks. yeah i will be the first to admit i've only spent like 2 days with htmx so i wont know everything (but still...)
re: hx-preserve. what if i want to "conditionally preserve" - preserve this element when my state is one way, but not in other states? i dont see a way.
re: hx-swap-oob. looking at https://htmx.org/attributes/hx-swap-oob/ i think it still does not address what i'm looking for. any master-detail list kind of UI will want updates in 2-3 places when 1 piece of state updates (aka ui consistency, ui as a function of state). i fail to see how attaching an attribute with 1 place for an ID solves that. perhaps theres another api for "multiswap"? even if it existed... idk if i'd be comfortable using it man (ofc, i am clearly biased/taught to "think in components" from 7 years of react exp)
You're misunderstanding hx-swap-oob. Each element with that attribute will go and replace the element with the matching ID, keeping them all in sync with one response from the server.
'preserve this element when my state is one way, but not in other states'
You could send the state back to the server with the request and respond appropriately on the backend. Or check in the db without sending it, if it lives in the db (it probably should?).
Google for AHA stack. (Astro, HTMX, Alpine) There was a great site by Flavio Copes that went into a lot of detail on using them together but it looks like it’s gone.
It's pretty good combo. I use Alpinejs for the client side interactivty such as modals, but then use htmx for as much as I can that interacts with the backend.
You could be using only htmx or only alpine but the combo is really nice
In that case, IIUC, state is managed on the server, and the client is only responsible for rendering views generated on the backend and returning user input via form or json. This is what htmx was really designed for, anyway.
I am not surprised around (1). HTMX is based on REST, which is by nature based towards having the state in the server and having a stateless client. But what is the advantage of having the state in the client. Isn't that just a bias of the current frameworks?
I can see cases where you really need a thick client, and in that case I would use GraphQL rather than REST for those. But, there are quite a few cases that can work with REST and mostly server side.
I think (2) is solved by out of band capabilities of HTMX. I don't think that is naturally a limitation of the conceptualisation.
The problem is that you need to remember every single place in your app that needs to be updated when you change state instead of your framework doing it for you. You said it yourself-- the "out of band capabilities". Instead of your UI automatically updating in reaction to a state change, you have to manually write out every single component's markup while being extra careful to make sure that each ID matches. [1]
This is why HTMX is ultimately an imperative framework. You have to wire everything up manually yourself instead of simply building a declarative representation of your UI and letting your framework handle the synchronization.
Did you ever use jQuery? The negative aspects are remarkably similar to the point that it is mildly amusing.
Regarding state on the client, my general concern is connectivity with the server. If I have a flaky mobile connection, or if I have a really high RTT to the server for any reason, then I don't want UI interactions to start failing or slowing down left and right. Indeed, a lot of the sluggishness I've experienced with others' websites has to do with excessive roundtrips for trivial tasks like clicking around. So I'd prefer to keep most UI state in the client, if nothing else. (Of course it's still quite possible to make excessive roundtrips with an SPA framework, but it naively seems like it's at least more controllable than if everything is rendered server-side.)
people give me grief all the time because i don't use proper capitalization in my texts. they even ridicule me if i say "you understand what i mean so who cares"
but i don't get to do the same thing when they say stupid shit like "smol". that's just normal, while i am retarded
Using capitalisation is actually reasonably useful for people with certian classes of disabilities, maybe concider it purely from the perspective.
So is breaking up things with whitespace which you did reasonably well.
So it's not a matter of "You know what I mean, so who cares?". They may realistically have had to put in significantly more effort into understanding what was written.
That isn't entirely true for something silly like the word smol.
i often avoid capitals myself in informal writing, but to be fair, there's a valid argument that period is pretty small and can be hard to spot by itself for something as important as the statement separator . capital letters help with that somewhat, although it doesn't help that we've overloaded them for other things . putting a space before the period helps keep it more distinct, but i really wish our punctuation was better designed (right after we reform english spelling i guess ...) .
but i digress . whataboutism aside, what's the actual problem ?
I agree with you. After seeing some internal prototypes at my job abusing htmx boost.
I'm slowly going on the anti-htmx bandwagon.
I'm still not pro-react or pro-vue. We need a stabler frontend js framework.
It seems like it makes easy things easy and hard things hard, which seems like a pretty poor value proposition - at least relative to some of the hype around it.
I think the takeaway here is "make the easy things easy, don't use it for the hard things".
One of the most exhausting things about any discussion about front end web dev is that it gets treated like a monolith. It _can_ be incredibly complicated. In many scenarios that complication is unwarranted. But in some it's justified.
Htmx is a poor choice for a full single page app. That's fine. It excels in other areas. Right tool for the right job.
But easy things are also relatively easy when using other tools that scale up better. Even if HTMX makes the easy things slightly easier, is that worth investing time and energy into learning it in addition to those tools that scale up better? Is it worth building things with it if I know that months down the line I'm going to need to scrap it once my easy thing becomes slightly less easy?
Like I said, this seems like a poor value proposition to me. Of course, if other people are happy with it more power to 'em.
To me it feels like people are eager to latch onto this because it's different, and because there's a dopamine hit associated with seeing the easy thing become a little easier when taking a new path that's overoptimized for it - hence the hype - not because it's actually good engineering, in terms of the tradeoffs you're making.
Of course, I feel the same way about Tailwind, so maybe I'm just old and grumpy.
Because it's a drop-in, no-dependency, no build-step library that can make your static MPA a little less static for the little bits of interactivity you need with not much effort. It's what you reach for to avoid "write the whole website in JS."
React -> "The site exists in JS, HTML is just a render target."
jQuery -> "Poke at the HTML from JS." Which is brittle as hell.
htmx -> "The site exists in HTML, extend HTML to handle the common tasks you want to do with it."
> Even if HTMX makes the easy things slightly easier, is that worth investing time and energy into learning it in addition to those tools that scale up better?
Depends what your aim is. Do you want to become a full time front end engineer? Then no, probably focus on other frameworks. But do you, from time to time, want to put small pieces of interactivity on web pages when it isn’t the sole (or even major) focus of your job? Htmx might be ideal.
For me the strength of htmx is to allow non JS languages and frameworks on the server side. Now I can use Raku+Cro+Red to make a modern website with dynamical modern UX. The standard paradigm is keep all state in isolated htmx state machines (eg modelling a form submission) or real state stored in my db and this works fine for my simple site needs.
> strength of htmx is to allow non JS languages and frameworks on the server side
I don't see how that has anything to do with the choice of htmlx. You always have the freedom to use any languages in the backend. If anything, htmlx imposes a bunch of hypermedia convention on top of your conventional API, regardless of languages.
Back-end devs think htmlx will allow them to be comfy in the back-end and just trash their front end with "thin client" that has no framework or any sort of organization. Eventually someone who is willing to actually think about front-end has to rebuild it and decouple the 2. Happens all the time.
I build quite basic websites for money. Today I use WordPress and write some combination of PHP/JavaScript with Advanced Custom Fields where I need custom storage. So tbh anything else has gotta be better! This means I have both front end and back end aspects under my personal control.
I want to be able to be able to code in a more natural back end setting - I like Raku, others may prefer Go (or Rust or PHP or JS). I am not ready to commit to a complex event driven framework like using the WordPress backend and React on the front end. But I do recognise that a pure browser only model for UX is too crummy … let’s say I want to validate an email … well if I specify input email in HTML, my browser will pop and ugly dialog if there is no @ in the input.
So HTMX gives me my backend coding preference and a clean way to add simply tweaks to the UX. That is the power of HTMX for me.
I don’t think HTMX is a good solution is you want to write Google Maps or Facebook. But it is a great way for straightforward sites to be written and I do not understand why I will be forced to step into JS front end rewrites if I go this route (and I can happily bundle some JS + CSS + HTML into an HTMX response for the islets where I need it.
> I want to be able to be able to code in a more natural back end setting
I think the point the OP is making is that very new frontend frameworks dictate what backend language you use. They just use HTTP requests and consume JSON.
On the contrary, making easy things easy and hard things possible is about as good of a value proposition as I can realistically expect. Hard things are going to be hard no matter what, and making them easy usually either adds excessive complexity or else makes easy things hard (if not impossible).
Making easy things easy and hard things possible is great, I agree...but that's not what I wrote. And I don't think that's what HTMX provides - it mostly gets in your way with the hard things.
Making hard things hard is a subset of making hard things possible. Better than making hard things impossible, which is the usual result of making easy things easy :)
> And I don't think that's what HTMX provides - it mostly gets in your way with the hard things.
And yet they're still possible. Like I said: hard things are going to be hard no matter what. Even if the hard things are harder, that's still a worthwhile tradeoff for maximizing the easy things.
I am a backend/ML engineer and tried using HTMX to create a website with:
* Search box
* Typeahead
* Instantly updating search results
It was super instructive. In the end, I realized HTMX was probably not the best tool for that job, but it really helped me bridge the gap between "I get in theory why we use JS on the FE" and "Ah, I can see why client side JS is the obvious choice for this".
Doesn't a searchbox with typeahead and instantly updating results still require a backend? Isn't that backend not the most important ingredient of this use-case?
Or did you send a large payload of objects to the frontend and have it indexed clientside with e.g. lunr.js?
I've used fuse.js for this, but for a use-case where we knew we had less than a hundred documents to index and where the access control was simple and the content reasonably stable. I'd never use this for a search feature in e.g. an admin backend or a large, content-rich webapp.
Yeah the "pure" backend side (DB/queries to it) was not a problem and something I was already comfortable with. I did not use a client JS library for filtering, I was trying to stick to pure HTML response routes as much as possible. In addition to the typeahead search I had some dropdown and radio toggle filters. I wanted these to all be reactive to each other, eg, you shouldn't be able to select the region "North America" if none of the current typeahead results have that as a region. I found this confusing to implement within the HTMX paradigm. I had a lot of HTML partial templates and had trouble mentally modeling how it was all fitting together.
TBF, probably partially a skill issue. But I know that just going back to a "normal" approach where my backend returned a huge payload and then I wrote the filtering/rendering in JS, was sooo much simpler to think about, even if it resulted in more total code.
I'm working on my first project with htmx and had a similar dilemma. The core issue is that the input form itself has some state, in terms of which options are selected or which options are available. Even in the case of a simple drop down, the user's selection can get cleared if they drill into a result and then hit the browser back button.
At first I was reaching for JS and this feels good—total control! But I wanted to challenge myself to use a hypermedia based approach, and in the end the outcome felt better.
One key insight was that I needed to rerender the form too when I returned the results. At first I only inserted the results into the page and left the form untouched. Later I also realized that if you want to encode the entire search in the url as parameters, then you need a way to render that combo of results and form state on page load anyway.
I guess where it can get tricky is with the templating system. I used FastHTML and wrote all my HTML as Python code. This gives the full expressiveness of the programming language, which is nice, but it seems that templating systems typically provide plenty of logic and control flow. A single template can do a lot. For your example of making only certain regions selectable depending on search results, you could pass the list of regions into the template engine and use a for loop capability in the template.
But hey, you found a way that works and that's great. Just wanted to share that I found with a bit of paradigm shift I found the hypermedia approach really straightforward and clean.
> At first I was reaching for JS and this feels good—total control! But I wanted to challenge myself to use a hypermedia based approach, and in the end the outcome felt better.
I've built a search page that used meilisearch as backend and a simple "SPA" in vanilla JS once.
It was completely "Hypermedia based" because I stored all the state of search/facets/pagination for the SPA in the URL(query args). A URL is limited in what it can store, but its a neat storage for state, especially because it's limited :)
Then if you landed on a page with certain query args, the state would be rebuilt from that, and the request to meilisearch would be constructed from this "state", sent there, and the objects in the response would be the state for the results.
What issues did you run into with this? I do exactly this in a couple of apps. You can use a `keyup changed delay:${delayMs}ms` event, and you target the area on your page where you want search results.
I also took that approach. The problem wasn't the keyup trigger, moreso trying to make the typeahead suggestions play nicely with radio/toggle filters, plus the results, made things really confusing for me personally. I was taking the approach of ONLY returning HTML from my endpoints and found it hard to mentally model how all the templates were fitting together (probably a skill issue, I am very new to webdev).
Once I abandoned the pure HTML/HTMX approach and just focused on returning a big payload with the search results in JSON and rendering it with vanilla JS, the whole thing became a lot easier.
I see a couple of people here bashing on the practicality of this project. That's obviously not the point, it's an interesting weird use case that's more explorative/educational than practical. I thought it was an interesting and inspiring read!
FWIW, as a hobbyist developer who never had a chance to learn React, I found HTMX really helpful to make my Flask projects more reactive without adding much complexity.
Yeah, I'm the same. HTMX may not be great for non-trivial work frontend devs are doing, but for hackers piecing together web interactivity, it's pretty nice!
I agree. I'm building some internal tools at work, and htmx is awesome when you just want to add a bit of interactivity to server side generated pages. With minimum amount of code I can just update the view by returning the relevant parts from the templating engine. It promotes code reuse and is faster to implement than any other framework based solution.
I'm not sure about this approach but it does look interesting. I think it'll work fine.
My method is however to use Django and templates to build a regular MPA, and then switch out link changes (between pages) with htmx functionality so there is no browser reload. At least then you'll have a webapp that acts mostly like an SPA.
Next up, you can add more interactivity using htmx as much as you want (with some kind of Django components, ideally). You can even add VueJS to one of the pages if you want, but full blown SPA frameworks tend to eat into development time, so rather not unless absolutely needed.
I don’t know if the article describes the best use of HTMX, but when I wanted to experiment with building an interactive physics application on the web that used Julia on the backend, it was a perfect fit. I could design the whole page without any javascript (almost):
I hope we build Single-page apps with iFrames one day like how the web originally used <frame>. Everyone only talks about iFrames as if their only purpose is cross-origin content and <frame> is forgotten.
No, thats the misconception. All the security is around cross-origin usage and optional if using same-origin html like a SPA. Each iframe gets its own window element but that can simplify component design a ton if embraced.
A <frame> was a system for loading same-origin html files from an Index. It was the original Single-page multi-page system and at the time seemed good enough for 90% of html 1.0 sites. <iframe> was supposed to replace it but then everyone used it for Ads and closed-source widgets.
I remember the days back when <frame> was still common, and I wouldn't call it good enough because of the way it interacted with URL and history. It was basically impossible to bookmark a specific page on a website that used frames.
It's a shame that was never solved because there is no reason it should be "impossible". Nowadays we have more control of URL and history. There must be a way.
Well, the way frames are specified, each has an URL in its own right, so the way to do it would be to come up with some algorithm that combines them all in a single URL without losing any data. The resulting URLs would inevitably be messy, though.
These days we basically hack around all this in JS by manually controlling history. Which is brittle as hell, and why so many web apps break "Back" etc.
Managing state is always a hard problem. Versionable extensible persistence is harder still. Now add the requirement that this state has to be captured in a concise but human-readable way, and it's really hard to do in a way that doesn't introduce numerous footguns. I'm not saying that there isn't some good solution, but I don't know what it is, and I don't think anyone has figured this out yet.
I think OP's point is that our current approaches are hacks around HTML - what the browser sees isn't individual components, but their combined output. It would sure be nice if this was something directly supported by browsers without the need for server-side frameworks.
People should stop treating the dom and browser abstraction as golden standard. It's just an abstration that happens to be standardized. Sometimes it makes sense to follow the standard, sometimes "the standard" is just too shitty to follow.
That's my point - if the standard is so shitty in this area that everybody reinvents this particular wheel in a hacky way, the standard should be improved.
That's cool but people need to ship products while their ideas for improvement are endlessly debated, bikeshedded and possibly rejected eventually.
At the end the standard is never what they exactly wanted. So it's kinda a futile effort, and for what? Most don't write code for 3rd party consumption, where standards shine.
I'm adding onto this: I think that the whole SPA concept is wrong most of the time. You want most of the time some sort of state persistence in the url, so that you can bookmark/pass around something that is meaningful, not something that is always the starting point of everything.
If I'm seeing a list of todos and I've filter actives there's really no benefit into not having the filters reflected in the url. The same goes if I'm navigating some data in the form of some table and I'm, let's say, at page 2.
The usual argument is that a well-written SPA will track its state correctly in the URL, including things like filters, current page etc.
The practical issue is that very few SPA apps actually do that consistently. Moreover, because it requires a conscious effort on behalf of developers, a fresh new app might be well-written in that regard, but over the years, as "got to fix this quickly for release" cruft piles up, it becomes worse and worse in that regard.
I think the only way to actually make this concept work reliably is to force people to store state in the URL somehow, or at least make that easier than storing it anywhere else.
HTMX is an idea that I never understood. HTML over the wire sounds like the most egregious idea I could have ever thought of. If you want a sub par SPA experience just build an SPA with PHP ;), and if you want a real SPA that doesnt have 600 ms of latency when I click a button that for some god forsaken reason calls an api endpoint, use React or Vue or Svelte like we always have. Is it perfect? Trust me, as someone who is trying to build something that delivers an actual SPA experience with SSR without Node.js, it's not, but a real SPA is miles better than streaming HTML over the wire.
I think I actually like what they are doing. They're using a combination of Stimulus and HTMX, which I think is a more valid approach than the approach that Hey (the email and calendars site) and many others take, where practically every interaction streams HTML over the wire as opposed to what David and his team are doing where it gets the information on page load so that you arent waiting around for content to come over the wire. I think this approach is how HTMX should be used, but it often is used in a similar fashion to how Hey works, and I think that's the major flaw, take what I say with a grain of salt, but I dont think HTMX pushes the idea that you should preload stuff very well.
For my own hobby useage - ie apps I shared with a few people - htmx is a godsend. It lets me focus most of my time in python/flask.
I do have a slightly more complicated TTRPG live character sheet that I use for a game I run. Its got five users at once and sqlite backend. Its gotten moderately more complicated over the last year and now sports htmx, discord integration, and will soon have SSE for me to push events to their character sheets, like ability point refreshes etc and other fun stuff without them having to refresh the page all the time.
I'm just thankful I don't have to dive into JS frameworks and can mostly stay in html, maybe a little hyperscript.
imo htmx is good but its a bit too low level to use directly, you sort of have to rebuild all the features frameworks like React have, such as components in your server programming language.
"Your scientists were so preoccupied with whether they could, they didn't stop to think if they should"
At that point, maybe stop fighting with service workers and simply use a framework like Vue. It allows html templates to be swapped in, in much the same way. Except you can actually debug it and store in localStorage if you desire.
Anyone who says React has mired developers in complexity needs to go back ten years and use jQuery to build a single-page app and remind themselves how much less complex React is. I know that because I rewrote a jQuery-based SPA in React back in 2015 and that experience was so revelatory that I will never forget it.
It is then that they will realize complexity comes from single-page apps. Pushing back against that complexity should result in not building SPAs, which is where Htmx comes in. There are still plenty of very successful web apps that are not SPAs.
If a product owner asks to build a SPA, a developer's job is to stop and ask why. Most likely what the product owner really has in mind can be accomplished without a SPA.
I’ve noticed there’s some mental block where managers and product owners behave as if adding new pages to a multipage app is too expensive so they just keep cramming more functionality into the existing half-dozen, dozen, or twenty pages. After three or more years it feels like you have a handful of single page apps, and jquery and many other tools struggle there.
in other words, this todo app is just about the most complex of a frontend you can easily* build with htmx, i'm afraid. try to fix either 1 or 2 and you end up building components and your own little framework.
as an exercise to demonstrate, try taking OPs code and adding a count of todos on each All/Active/Completed tab that should update every time u add/edit/delete the todos. see how much extra ui code that takes. compare with equivalent [framework of choice] impl (in most it will just involve 1 state update, thats it). this is htmx's explosion of complexity that makes it not [ optimized for change ] (https://overreacted.io/optimized-for-change/). code that is hard to change eventually calcifies and consumes code that is easy to change if you do not consistently garbage collect (nobody does)
i bought the hype too until i tried building something nontrivial in htmx and im afraid the aforementioned islands of interactivity you can build are very very smol islands indeed.
happy to revisit my opinion if there are componentlike design patterns in htmx i am not aware of.
*emphasis on easily; with enough elbow grease u can do anything ofc. but then you fall out of htmx's very narrow [ pit of success ](obligatory codinghorror dot com link)