Every Friday morning, some junior developer trying to get noticed drops yet another “Top JavaScript Frameworks” list.
Same line-up every time: Angular, React, Vue, Svelte, maybe Solid if they’re feeling bold. It’s like Groundhog Day for frontend devs.
So let’s break the loop, shall we?
Here are three frameworks/UI libraries that don’t quite play by the rules. Each one does things in a surprisingly different way that's worth a note.
To run a comparison, we’ll pick a random UI task and see what their approach is like: let's create two buttons that, when both clicked, enable a third one.
HTMX — The Antiscript
Some people believe HTMX is here to kill JavaScript, but what it really wants is to stop you writing it.
Instead of functions and event listeners, you describe behaviour directly in your HTML using attributes like hx-get
, hx-trigger
, and hx-swap
. It lets HTML talk to your backend — no scripts, no build tools, just markup that acts.
Here’s how the same two-buttons-unlock-third example would look in HTMX’s world:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
</head>
<body>
<div id="app" hx-get="/buttons" hx-trigger="load" hx-swap="outerHTML"></div>
</body>
</html>
And on the server, you’d have something like this (using Express for simplicity):
import express from 'express';
const app = express();
let clicked1 = false;
let clicked2 = false;
function renderButtons() {
const bothClicked = clicked1 && clicked2;
return `
<div id="app">
<button hx-post="/click1" hx-swap="outerHTML" hx-target="#app">Button 1 ${clicked1 ? '✔️' : ''}</button>
<button hx-post="/click2" hx-swap="outerHTML" hx-target="#app">Button 2 ${clicked2 ? '✔️' : ''}</button>
<button ${bothClicked ? '' : 'disabled'}>Button 3</button>
</div>`;
}
app.get('/buttons', (req, res) => {
res.send(renderButtons());
});
app.post('/click1', (req, res) => {
clicked1 = true;
res.send(renderButtons());
});
app.post('/click2', (req, res) => {
clicked2 = true;
res.send(renderButtons());
});
app.listen(3000);
Each button click sends a small POST request to the server, which updates its state and sends back the new HTML fragment. The browser replaces the old section automatically.
That’s the real spirit of HTMX: make HTML dynamic again, by letting the backend do the work.
Hyperscript — Like plain English
From the same folks behind HTMX comes Hyperscript.
If HTMX is "HTML that acts", Hyperscript is "HTML that talks".
You literally write scripts in plain English:
on click add .active to me`, `wait 2s`, `remove @disabled from #btn3`
Readable, no build step, no imports, no framework gymnastics.
It’s imperative, surprisingly expressive, and kind of brilliant in its simplicity.
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
</head>
<body>
<div id="app">
<button id="btn1" _="on click add .clicked to me then call check()">Button 1</button>
<button id="btn2" _="on click add .clicked to me then call check()">Button 2</button>
<button id="btn3" disabled>Button 3</button>
</div>
<script type="text/hyperscript">
def check()
if #btn1.hasClass("clicked") and #btn2.hasClass("clicked")
remove @disabled from #btn3
end
end
</script>
</body>
</html>
That’s HTML that reads like English and behaves like JavaScript.
It doesn’t try to abstract your logic — it just makes it human-readable.
Rimmel — The Stream-Oriented One
Third on the list is Rimmel, and it’s playing quite the opposite game.
Rimmel is built on the idea that "everything is a stream".
No state objects, no virtual DOMs, just continuous flows of data that describe how your app reacts over time.
If you’ve ever worked with both RxJS and React, you’ll feel unusually comfortable for today's JavaScript standards.
import { BehaviorSubject, combineLatest, map } from "rxjs";
import { rml } from "rimmel";
const Component = () => {
const first = new BehaviorSubject(false);
const second = new BehaviorSubject(false);
const disabled3 = combineLatest({first, second}).pipe(
map(({first, second}) => !(first && second))
);
return rml`
<div>
<button onclick="${first}">Click</button>
<button onclick="${second}">Both</button>
<button disabled="${disabled3}">To enable</button>
</div>
`;
};
document.getElementById('app').innerHTML = Component();
There’s no diffing, no re-rendering, no setState
. Just events and data flowing as reactive streams.
It’s pioneering a novel paradigm — Stream-Oriented Programming — and it flips the whole idea of "UI logic" on its head.
Which One Fits You
If you like HTML doing the heavy lifting you may have a very good time with HTMX.
If you want to try the breeze of scripting in plain English, perhaps you're writing something for non-developers, Hyperscript is genuinely refreshing.
If you can think of events and data in terms of streams, if you want total control and you're creating complex applications, you may rely on Rimmel's strong computational model.
The Small Print
HTMX keeps HTML front and centre, but it only gets you so far — real logic still needs scripting and your users better have a fast, reliable internet connection that's always on.
Hyperscript bridges that gap in a surprisingly natural way, though it’s best for small to medium projects. Complex logic is still complex logic. Don't expect everyone to understand it just because it's English.
Rimmel shines for its sound computational model. It's simple to start, it's rock-solid at scale, but you need to learn how streams and RxJS work if you haven't already, which aren't exactly as simple as plain English.
So, now we found a few frameworks that don’t try to be “the next React”. They’re doing their own thing, greatly challenging the status quo — and that’s what makes them worth knowing.
Can you suggest other frameworks/UI libraries that break all rules and bring something truly different to the scene?
Top comments (0)