Let's make the worst Htmx

Posted by RebelPotato 3 days ago

Counter140Comment75OpenOriginal

Comments

Comment by Aeolos 2 days ago

I highly recommend everyone to give htmx or datastar a try, especially if your main experience is react or nextjs.

We recently rewrote a half-million LOC codebase from react to datastar, with a detour through htmx first, and the results are staggering.

First page load is 20KB down from a 750KB js bundle. 1 network request vs 40+. Total load time 0.1 seconds down from 2 seconds of spinners. Page refresh is so fast, the browser doesn’t even flash - there’s no massive js bundle to parse, so it can start rendering instantly.

But the most staggering result is that in-document navigation over SSE achieves up to 5000:1 compression ratio for network requests within the Brotli compression window. Yes, 5000:1, you read that right. When changing server state we rerender the entire page, like an immediate-mode game engine, and push it to the client over an SSE “fat morph”, in about 100 bytes.

It’s so fast and so much more stable, our users are literally having fun. With a medical device.

And this ends up ~50% less code to maintain for a VASTLY superior UIX.

You are really missing out if you don’t learn how this works. It can give you a significant competitive edge if you care enough to try.

Edit: Big BIG thanks to bigskysoftware and the datastar team for making the web a sane place again. You really deserve all the props.

Comment by andersmurphy 2 days ago

My experience was similar. I'd wound down a startup and as a solo developer could no longer afford to do react + a backend. So I tried HTMX, then turbo (which introduced me to morph and push based re-fetch). Finally moved to datastar because I could drop alpine and it has best in class morph, signals and SSE support. Immediate mode over the network is amazing DX.

Makes multiplayer out of the box over large datasets trivial. See these demos if you don't believe me [1][2] (open them in multiple tabs and have fun)

[1] https://checkboxes.andersmurphy.com

[2] https://example.andersmurphy.com

Comment by vlucas 4 hours ago

If anyone is looking for a TypeScript framework that embraces hypermedia the same way that HTMX does (and is very easy to use with HTMX), check out Hyperspan: https://www.hyperspan.dev

Disclaimer: I built Hyperspan :)

Comment by bramhaag 2 days ago

Since you tried both, what made you choose datastar over htmx?

Comment by Aeolos 2 days ago

Our UI is highly interactive: think 3d visualizations with toggle-able overlays, various display settings, searchable lists, drawing tools etc.

We made a lot of progress with htmx, but eventually hit a complexity wall where we were spending more time fighting the tool than solving the business need. Note, I'm not blaming htmx here, the documentation is clear about its strengths and limitations, and the hypermedia approach is still fundamentally right. But even with alpinejs in the mix, we just weren't able to achieve the smooth developer experience we were looking for.

So we tried datastar, and it basically addressed all the friction points we had:

  - No more DOM hunting to figure out why the hx-get ended up in the wrong spot or why OOB swap is glitching out. D* morph just works.
  - No need for hidden form <input> to submit client state, D* signals are cleaner and easier to use.
  - No more micro-routes for targeted element updates to avoid hx-swap butchering page state. One route per page, just render the whole thing and morph takes care of the rest. Immediate-mode rendering and fat morphs removed ~50% of our routing table.
  - SSE + fat morph is a superpower. This is view = f(state) done right.
We've had very few issues, D* just works and gets out your way. The team has really created something quite exceptional.

The great news is htmx4 is adopting many of these ideas, so I recommend trying both and seeing what fits you best.

Comment by andersmurphy 2 days ago

It's nice to see HTMX4 is adopting the core strengths of Datastar. That sort of cross pollination of ideas is a huge boon to the wider hypermedia community in general.

Comment by sudodevnull 2 days ago

HTMX v4 doesn't actually address what's makes Datastar work at it's core. It at best it copies some of the broad strokes of the API but not in a robust it efficient spec compliant way

Comment by andersmurphy 2 days ago

A focus on morph by default means you don't have an explosion of endpoints and can write programs like the 300 redirect days. [1]

Once you want realtime/collaborative app SSE + morph lets you do that easily. Add streaming compression and this approach is suddenly crazy bandwidth efficient.

For people coming from react this gives you v = f(state) over the wire.

Lastly signals handle the edge cases where an out of bound morph would nuke your ephemeral client side state (mostly text input).

You can do this in htmx but you are fighting the design the whole way. Turbo is a bit better but doesn't have signals.

[1] https://dev.37signals.com/a-happier-happy-path-in-turbo-with...

Comment by JSR_FDED 2 days ago

I’m getting about 800:1 compression with Brotli. I wonder if need to tune anything? Although tbh I have no performance issues at all.

It took me a minute to change my mindset to Datastar’s way of doing things. But it’s been amazing. Firstly to keep 99% of the state and logic on the back end is just so nice - no more having to deal with two sources of state at the same time (front end and back end). Secondly the ability to regenerate the entire view from scratch anytime something changes and then have Datastar efficiently morph just the changes is just such a simple mental model. Every fiber in me was like “no way that can work, the cpu, bandwidth, latency etc” - but it is buttery smooth.

Comment by andersmurphy 2 days ago

So compression ratios with streaming compression (brotli/zstd) come down to the regularity of the data, the size of the change, and the size of your window.

Basically, if your html fat morph frames are 65kb uncompressed and you make a small change like checkbox it will send 13bytes so that's 5000:1. Caveat is as long as your compression context window is big enough.

Comment by halfcat 2 days ago

How do you debug SSE messages since they don’t show up in chrome dev tools with Datastar?

Comment by Aeolos 2 days ago

You either buy a datastar license to get their debug tools, or you spend a couple of hours to build your own. I'm sure you can find something on GitHub too.

One of the cool things is how extensible d* is. Everything is a plugin, and you are free to extend it to suite your needs. We've invested a few days building a few specific data-* attributes for our application and it's super convenient.

Comment by cpburns2009 2 days ago

I really want to try htmx but it specifically prohibits my most common usecases:

1) I want to take a JSON response, create HTML from it, and replace the target element with the generated HTML.

2) Similar to the above, take a JSON response, perform some action, and do nothing to the source element.

Is there a plugin to add this? I want to move away from jQuery, and having a small framework to wire up hooks would be useful.

Comment by masfoobar 3 hours ago

Sounds like you are going through similar struggles as a few backend developers I had trying out htmx. Years of muscle memory with returning JSON and letting the frontend (javascript/jquery) to handle the html.

They were making a big deal with this change. In the end the change is rather minimal. The outcome is reduced javascript code and more server side html templates. Pretty much most of the code is now handled on the server side. Just organise the html templates!

Pseudo example

Instead of :-

<code>

// returning as Json

[Get]

Response GetUser(int id) {

   var user = getUser(id);

   return ToJson(user);
}

</code>

You are just doing :-

<code>

// returning as HTML

[Get]

Response GetUser(int id) {

   var user = getUser(id);

   return View("som-user-template", user);
}

</code>

I don't know what 'hooks' you need, but whatever they are doing you can move them over to returning/updating section of html on the screen with htmx.

Comment by cpburns2009 15 minutes ago

By wiring up hooks I just mean binding a callback to a button that calls fetch() and processing the response (usually replacing HTML, but may modify content and classes on other elements). Basically what I'm looking for is being able to specify a callback (ideally just a global name set from HTML) that will be called with a response object when JSON is returned. I prefer most coding to happen server side, but sometimes client side JS is needed.

Comment by igor47 1 day ago

Why are you so wedded to JSON responses? HTMX is meant to be used to render html; my big HTMX app basically never(1) renders JSON, so much so that I have a standing instruction to coding agents that if they're rendering JSON they're probably doing something wrong. If you're attached to JSON because you're working with external API s you don't control, a good place to perform those kinds of actions is in your backend, which can then return html to your frontend

(1) the exception is I think in one place concerned a flow for uploading images, where client side requests a signed url, uploads to that url, then registers completion. Getting the signed url back is JSON meant for the uploader

Comment by cpburns2009 23 hours ago

I want to handle a JSON response because I usually return data for multiple page elements. These aren't external APIs, they're requests to the backend server.

A simple example is adding a note to a product or order. When you submit it, it gets inlined, and say a visual note counter is incremented. Usually I'll return multiple HTML fragments if it's convenient, but I'll return a data structure if needed.

Comment by Doxin 3 hours ago

You can return data for multiple page elements with HTMX too using the "OOB" mechanism.

Comment by wasting_time 1 day ago

I made a UI with htmx, it works great.

But now I want to add a JSON API to the program: I could reuse the same routes (/create, etc), but require an application+json header; or add a full /api/ component essentially duplicating the logic from the main app.

Neither option is great.

Comment by Aeolos 1 day ago

Fat services, thin routes. Try moving your business logic to a library and consume it from both your UI and API routes. That minimizes duplication and decouples your public API resolvers (with backwards compatibility requirements etc) from your private UI resolvers (which you want to evolve rapidly to optimize your UIX).

That's what we did and it works pretty well in practice.

Comment by igor47 1 day ago

I do get kind of annoyed that htmx submits forms using form url encoding. It's non trivial to validate, see https://igor.moomers.org/posts/zod-schemas-htmx

As a result for POST requests you have to have htmx routes that accept urlencode and API routes that accept JSON, and JSON is far superior. But for outputs I actually think separating your UI and API is helpful. The code reuse is not worth the entanglement of concerns.

Comment by yawaramin 1 day ago

Ok, for the sake of completeness–why do you want to add a JSON API to the program? Quite a lot depends on the reason.

Comment by wasting_time 1 day ago

It's a service, and I want to add a CLI for humans and agents. Aeolos' reply makes a lot of sense, I can refactor the backend into a library and add thin UI and API routes on top of it.

Comment by gofreddygo 1 day ago

Why are you so wedded to JSON responses?

I'd assume because of the conception that json = data. Html = presentation. But if you just use barebones html, this could work very well. Just add a wrapper in the api to return json as html to try it out a bit.

Comment by worthless-trash 2 days ago

They didnt mention the real side benefit of HTMX, and thats the twitter account memes.

Comment by brettermeier 2 days ago

Nice, I really like this series, this made me really understand those web frameworks much better as before. Thank you.

Comment by stevoski 1 day ago

Part of the beauty of htmx is how simple it is to recreate. As this post shows, the fundamental concepts of htmx really are straightforward.

Of course, there are all sorts of edge cases and minor features to add to make it complete.

Comment by n4pw01f 2 days ago

Have a pretty large application running HTMX + WebComponents + Hono + Cloud Functions to serve up frontends, happy with it for about 2 years now

People throw salt at my stack but it’s fast, and straightforward to manage attack surface

Comment by esperent 2 days ago

I'm using Hono + Tanstack Router as a Next.js replacement. Best software related decision I ever made, it feels like I stopped fighting with the stack.

Comment by ErroneousBosh 2 days ago

I wrote a really tiny web app using Django and HTMX to do a find-as-you-type telephone directory, and it worked really well.

I wish I did more front-end stuff so I could play with it more.

Comment by cyanregiment 2 days ago

HTMX is amazing on paper, not in real life.

It loses things like scroll position and text highlighting on re-render - it’s not high performance like React.

This is for server sided or static web pages not building rich UI.

There is no robust state management or DOM performance improvements you get with React with larger components.

HTMX team should build a game with it. Load some 3D in WebGL/WebGPU, showcase high performance UI.

Or showcase complex state management.

I need more than syntax idealism.

Comment by vb-8448 2 days ago

> HTMX team should build a game with it. Load some 3D in WebGL/WebGPU, showcase high performance UI.

Why? Why you'd pick htmx (or even reactjs?!?) to build a game?

Comment by cyanregiment 2 days ago

Because I would need to see a UI paradigm prove it can handle performance before considering using it for UI.

react-three-fiber solves a lot of problems. React state is also perfectly in line with game loop architecture, r3f unifying the Three.js/React render loop is incredibly good for game dev.

But even for SaaS or whatever, I need to know that it can handle complex states of the UI - HTMX can't.

They are overselling it. It's not really a competitor to React, it's more like a competitor to Jade templating or HAML which nobody already uses anymore.

Comment by yawaramin 1 day ago

> They are overselling it.

They quite literally have a a large essay on their site dedicated to discussing when to and when not to use it: https://htmx.org/essays/when-to-use-hypermedia/

Also, it’s not at all sold as a ‘competitor to React’, it’s sold as a simpler option for many apps where React is overkill. If you want to make a game with React, no one will argue for using htmx instead. The game will probably have a lot of perf issues though.

Comment by vb-8448 2 days ago

If I have to build something that is basically logic on backend, forms, tables, some static pages, some interactivity here and there(btw is what most of the sites and web apps out there are) I don't need 3d or game engine capabilities ...

And no way react is going to be faster for the above use case.

You miss the point of tools like htmx/datastar/turbo/unpoly/alpine, they are not a react competitor in the rich and complex web apps space. They fill a gap between the native browser capabilities and tools like react/vue/svelte/ecc.

Comment by Aeolos 2 days ago

Having used both in anger, I find d* has a lot of very real advantages over react if you care about performance and application stability.

It's simple enough that you don't need training or lengthy guides about "the rules of books etc".

It's small enough that an LLM can store the entire thing in context and answer your questions.

And it doesn't npm or a build step.

Comment by cyanregiment 2 days ago

HTMX makes it hard to build even basic things, because it swaps entire HTML forcing a full repaint. That's the foundation of how it works.

Examples include user highlighting text - swap wipes that out. Or user mid scroll through a menu, the scroll is reset to the top.

It's not enough in HTMX to just break it down into smaller components, the scrolling part is native to the browser, so is text selection.

Some people forget or don't know how much an SPA library like React is doing to prepare the SPA before you get into any of the organizational framework usage. Beyond that, clever engineering went into React DOM reconciliation in particular that I rarely see challenged in other libraries.

On game dev: I think it's good for a showcase because it shows the limits of what it could do at 60+ fps in a performance intensive environment. But yeah, even a complex SaaS demo would do.

> They fill a gap between the native browser capabilities and tools like react/vue/svelte/ecc.

Have not heard that yet, since a big part of HTMX is manipulating the DOM and binding events. I'm pretty sure this is not correct

Comment by vb-8448 2 days ago

> Have not heard that yet, since a big part of HTMX is manipulating the DOM and binding events. I'm pretty sure this is not correct

Did you ever open the htmx home page? Because it's at the very top in the "motivation" section!

I'm starting to wonder whether you're trolling or you have no idea what HTMX and similar tools actually do.

Comment by cyanregiment 2 days ago

Google result for "htmx with react"

"HTMX and React represent fundamentally different web development architectures, but they can be compared or even used together in a hybrid setup."

I see tutorials on how you can mix it with React for Next.js which might make sense at the page level because it's SSR.

Definitely possible, sure. But it would be about like mixing Angular with React where two libraries are competing for the truth of what's in the DOM.

There was a time Three.js "couldn't work" with React because they each had their own separate render lifecycles - but r3f happened with enough demand (and useFrame bridged the two beautifully).

Maybe the same will be true of HTMX, maybe people are actually trying to do that now for some reason, but yeah a lot would have to change with either React or HTMX to get value out of both simultaneously for UI.

Comment by ironmagma 1 day ago

Probably because the news of frontend's death has been overstated.

Comment by AlexeyBelov 1 day ago

How does this answer the question? I cannot imagine an internal monologue going like this:

- Hm, maybe I should use react for this

- ok, why react?

- because the news of frontend's death has been overstated

???

Comment by ironmagma 1 day ago

- Why would you pick $backend technology?

- Because someone told me frontend was dead.

Comment by yawaramin 1 day ago

Htmx is not meant for these use cases. We’re building great interactive webapps with htmx using the web platform’s built-in capabilities. If you need exact scroll position and text highlighting you can get that with some other framework. Htmx works well with things that are in its own niche.

Comment by sparse-Matrix 3 days ago

Bravo! I never would have thought this would be so simple. As a direct consequence of this exercise: I now know something about what, precisely, htmx does.

cheers

Comment by wren6991 3 days ago

Huh, so every interactive event has a network request in the loop, with perceptible latency? And you still end up obligating client-side JS for the plumbing? I'd been meaning to look into HTMX but based on the content of this post it seems like a worst-of-all-worlds technical solution. Is it at least pleasant to work with?

Comment by yawaramin 3 days ago

No, every interactive event doesn't need to have a network request in the loop. And you only need a tiny bit of client-side JS for a most of the plumbing.

It is quite pleasant to work with, because you don't have to worry about a constant stream of vulnerabilities or supply chain attacks. You just vendornthe script in your repo, add it as a <script> tag on the page, and you're done.

Comment by Rohansi 2 days ago

Supply chain attacks are not a JavaScript or npm exclusive risk. If you pull in any dependencies you have a supply chain risk.

Comment by barrkel 2 days ago

As is well known, security is not a binary, it's a spectrum. It's why you add security in layers, and why it's generally a trade-off between risk and usability.

Your mileage may vary, but I sleep better with my own projects not having any node_modules in their build tree.

Comment by robertoandred 2 days ago

How is htmx invulnerable to vulnerabilities and attacks?

Comment by stymaar 2 days ago

It's not invulnerable, I think gp just means that reducing your amount of dependencies reduces the attack surface.

Comment by deadbabe 2 days ago

Who is worrying? If JavaScript is on the front end the supply chain attacks are really not your problem.

Comment by cpburns2009 2 days ago

The supply chain attacks you need to worry about come from using npm.

Comment by Rohansi 2 days ago

No, it's not specifically npm. All package managers enable remote code execution by design - you tell it to download code and then you run that code, likely without sandboxing, by using it. Most people are not inspecting the code before they download and run it. You will still see compromised packages making their way through npm even though they disabled install scripts.

Comment by cpburns2009 2 days ago

I agree. I just pointed out npm because it's the most prominent javascript one.

Comment by traverseda 2 days ago

What? It handles your password fields.

Comment by deadbabe 2 days ago

Just do SSO.

Comment by yawaramin 1 day ago

Just do passkeys.

Comment by dmoreno 3 days ago

That's why many times HTMX is used together with alpinejs [1].

For areas that need server side, if you use say react and return a JSON you have to deserialize and do the render. It might be much more efficient to just replace.

Having said that I use HTMX /alpinejs for small projects, and still trust react for bigger more interactive ones.

[1] https://alpinejs.dev/

Comment by simonbarker87 2 days ago

It’s only has a network request in the loop if the interaction requires a network request.

Htmx is a replacement for network interactions, not every bit of UI interactivity.

Comment by muvlon 2 days ago

It's for building extremely backend-brained frontend stuff, like a sort of anti-NextJS. Also like NextJS, this sort of domain-bending has some unfortunate operational consequences.

Comment by draw_down 2 days ago

[dead]

Comment by inigyou 2 days ago

the network is faster than so much shitty client-side JS these days.

Comment by grebc 2 days ago

When you say these days, I’d argue since mid/late 2000’s for internet with a cable vs. radio waves.

Radio waves caught up in developed countries with 4G roll outs in my opinion(is that mid 2010’s?).

Large client side JS has been garbage for most things since it’s inception.

Comment by 2 days ago

Comment by JSR_FDED 2 days ago

Datastar has a lean and mean signals implementation that handles all the front-end reactive stuff - so you don’t have to go to the server for interactivity.

Comment by yyyk 2 days ago

The problem with HTMX is not network traffic but needing to use hyperscript for anything advanced.

Comment by antihero 2 days ago

Also don't you entirely lose typing?

My favourite thing about TSX is that it is typechecked. How do you do that with random strings of HTML?

Comment by igor47 18 hours ago

I still write tsx and my components look very similar to react -- just no hooks. The difference is I render to html server side and send the rendered html. Look into it in hono

Comment by pixel_popping 3 days ago

The Github link at the bottom contains a `,` char, might want to fix it.

Comment by oaxacaoaxaca 2 days ago

>Or you can just use htmx?

great idea thank you for the recommendation

Comment by htmxxx 2 days ago

We already have the naughtiest htmx

https://github.com/bigguysoftware/htmxxx

Comment by sodapopcan 2 days ago

Is there something known wrong with github rn (aside from everything, I guess)? It claims there are 422 contributors but when you click in there are only three.

Comment by ameliaquining 2 days ago

Change the period from "last 3 months" to "all".

Comment by sodapopcan 2 days ago

I did. Still 3.

But then I'd ask my original question that I didn't post: how the hell does this repo have 422 contributors?

Comment by ameliaquining 2 days ago

You're seeing only three contributors at https://github.com/bigguysoftware/htmxxx/graphs/contributors...? I have no explanation for that, it doesn't match what I'm seeing.

GitHub's contributor graph is based on authorship of Git commits, and doesn't track whether a given GitHub account ever actually interacted with a given GitHub repo. This Git repo is a fork of the htmx Git repo (though it's not marked as such on GitHub), so all contributors to htmx as of the fork date are also contributors here.

Comment by sodapopcan 2 days ago

Ahhh makes sense if it's a fork. Odd that it's not marked as one. Sort of an odd thing that you can get associated with a repo you don't even know exists.

Thanks for engaging me and my confusion.

Comment by roundwego 2 days ago

[flagged]

Comment by andy_parhelia 3 days ago

[flagged]

Comment by dang 2 days ago

Can you please not post AI-generated or AI-edited comments to HN? It's not allowed here - see https://news.ycombinator.com/newsguidelines.html#generated and https://news.ycombinator.com/item?id=47340079.

Of course, it's impossible to know for sure what was LLM processed or not, but some of your posts (like this one) have been getting classified that way.