23 comments

[ 2.3 ms ] story [ 43.9 ms ] thread
> htmx 2.0 (like htmx 1.0 & intercooler.js 1.0) will be supported in perpetuity, so there is absolutely no pressure to upgrade your application: if htmx 2.0 is satisfying your hypermedia needs, you can stick with it

This is commendable, specially during times when libraries and programs aren't afraid of breaking changes and API churn.

The only big gripe I have about htmx is that the hx-on::after-request response it provides to your callback function does not automatically parse JSON content types like with e.g. jQuery.ajax(). Last time I brought that up, people simply questioned why I would ever want to do that in the first place.
> So, eventually & reluctantly, I have changed my mind: there will be another major version of htmx.

> However, in order to keep my word that there will not be a htmx 3.0, the next release will instead be htmx 4.0.

technically correct.. the best kind of correct

Great to see this evolution! Realtime ssr hypermedia is definitely the future.

But, my thoughts immediately go to Datastar, which has Fetch, SSE, declarative signals and js expressions, dom morphing, and much more - in a tiny package. I find it to have a more flexible, expressive and standards-compliant API as well. And it'll soon have a simple reactive web components and css framework as well.

At this point, why use HTMX when it really seems like (a heavier) Datastar-lite?

I took a look at Datastar, and pretty quickly realized I really don't like libraries which try to do so many different things. The surface area of the API is way too big. htmx is already too big for me, I tend to reach for mostly vanilla-only or small vanilla-adjacent solutions I can either write by hand or import. But as I've been experimenting with htmx (including its very good extensions API), I'm realizing it's in a pretty good sweet spot overall.

I'm very excited about htmx 4.0 and sounds like things are headed in a promising direction.

> hx-target attribute is explicitly declared as inherited on the enclosing div and, if it wasn’t, the button elements would not inherit the target from it.

So confusing. I'm pretty sure it should be "inheritable", because "inherited" on an attribute means the attribute is inherited, not the element's children will inherit the attribute.

UPDATE: or "inherit", sounds like a command, little less confusing.

> By switching to fetch(), we can take advantage of its support for readable streams, which allow for a stream of content to be swapped into the DOM, rather than a single response.

Based on this section, it will be interesting to see how this evolves. I've used HTMX a bunch but after stumbling on Datastar I've come to prefer it. Partially because I don't need something like alpine.js to get some frontend goodies but also because I've come to appreciate the power of SSE streaming morphable targets to the browser

I really enjoyed reading this - very clear technical writing and I learned quite a bit about htmx and their approach to API design generally from it.
Interesting timing - I'm building genx.software which leans hard into implicit inheritance for the exact reason he is abandoning it. In my finance app, when the product owner changes their mind about decimal places for the 47th time (and it's always 47), the last thing I want is to hunt down every cell and add :inherited modifiers.

We treat everything as integers server-side (because floating point is the devil) and defer all formatting to the client. Implicit cascade means I can change fmt-x="currency:USD:decimals:2" in one place and watch it ripple down the entire table. It's 'maddening' the way CSS is maddening - which is to say, it becomes second nature after you stop fighting it.

That said, I fully understand the support ticket burden. Maybe the real lesson is: implicit inheritance is great when you control the domain (like 'format all money the same way'), but terrible when people want to do arbitrary things at arbitrary levels. I will bear that in mind as I complete genx.software

Neato. Sensible updates, no loss of support for previous versions? The software dream.
The image breaks the website on mobile for me.
htmx hasn’t had the piss taken out of it enough.
I was just about to use this for a feature but i won't bother now, it won't pass the stability test. Thanks I guess.
I feel like people who crave stability pull all the wrong lessons from how to get to stability when doing this sort of "ok we'll make _one_ major version with all the breaking changes we've built up over time".

This feels like a repeat of the Python 3.0 strategy, though obviously at a much smaller scale. Some stuff is of course hard to roll out but to me it feels "obvious" that having a 4.0 with the inheritence change (or even better, a 2.1 with a toggle on that change!), then a 5.0 with some other changes, then a 6.0 with other changes... all feels way easier to manage than a 4.0 with all the changes at once.

We have version pinning! People who want 2.0 can have 2.0 "forever", so version numbers that go up very high are not actually a problem. Many releases can of course be a bit of a frustration from a release maker's perspective, but given that htmx is the way it is (ain't even getting type checking helping you out on any of this like you would with React!), having the gradual path seems way better.

"I think I've handled the 10 changes in between 2.0 and 4.0... but forgot the 11th change" is a constant annoyance with these huge major version bumps.

I will once again point to the Django strategy of having breaking changes be rolled out over several releases, including in between releases where "both" models exist. It is a very nice way to do release management when rolling things out, gives good checkpoints for pushing things out, and overall means users are seeing less bugs. Going from `XMLHttpRequest` to `fetch` really might not be a feasable thing to toggle, but a lot of the other stuff in that list feels like it.

I think the ideas behind HTMX are cool, and Carson’s advocacy around Hypermedia is great.

I came from SPA-land and was tired of the fundamental architectural issue of having to keep the front-end and back-end state in sync.

I’ve compared Datastar and HTMX and decided on Datastar. There’s overlap between the two libraries in that they both support the request/response model, but with Datastar my learning investment takes me further and opens up new possibilities.

In one project I was able to remove a bunch of polling code and simply push a signal from the server to the browser when an external event occurred. The reduction in complexity was crazy.

On an internal tool I noticed I didn’t need Alpine.js anymore, and while anytime I can remove a dependency is a good time, the conceptual simplicity is what really makes me happy.

Now I’m doing a small app where I decided to make a streaming connection between browser and server and simply regenerate and send the entire view over that connection anytime something changes. Intuitively this felt wasteful but it turned out that with compression this works beautifully. There’s just less code in my app, and the code that’s there is less “fiddly” not having to deal with partial updates of the page.

If you’re coming from the world of SPAs, definitely check out both.

> In 4.0, with the complexity savings we achieved by moving to fetch(), we can now comfortably fit a morphInner and morphOuter swap into core

It seems odd to me to treat these as different properties on their own? might as well keep it as an extension if it is not going to be more deeply integrated and let htmx 4.0 be smaller? Possible I may not be understanding the use case though

Computer works in binary

htmx 1 htmx 2 htmx 4

I look forward to version 8 in 2030.

(Meaning there always was a version 3! Just include both htmx1 and htmx2 onto your webpage!)

Hopefully one day we will see htmx 4.0 being merged into HTML Spec.