The pendulum has swung back from heavy JavaScript frameworks — htmx, Alpine.js, and vanilla JS each represent a different philosophy on how much JavaScript your web app actually needs. htmx gives you AJAX, WebSockets, and CSS transitions via HTML attributes. Alpine.js adds Vue-like reactivity directly in your markup. Vanilla JS uses the platform APIs. This comparison helps you pick the right level of simplicity for your project.
Quick Comparison
| Feature | htmx | Alpine.js | Vanilla JS (ES2024+) |
|---|---|---|---|
| Philosophy | Hypermedia-driven: HTML as the engine of application state | Reactive sprinkles: minimal JS for interactivity | Use the platform: no build step, no dependency |
| Size (min + gzip) | ~14KB | ~15KB | 0KB (but you write more code) |
| Reactivity | None (server-driven state via HTML swaps) | Yes (x-data, x-bind, x-effect — Vue-like) | Manual (DOM manipulation, events) |
| AJAX / Server Interaction | Core feature (hx-get, hx-post, hx-trigger) | Manual (fetch() in x-data or Alpine methods) | Manual (fetch(), XMLHttpRequest) |
| DOM Swapping | Core feature (hx-swap, hx-target, transitions) | Manual (x-if, x-show, but you manage DOM) | Manual (innerHTML, createElement, replaceChild) |
| CSS Transitions | Built-in (class-tools extension) | Built-in (x-transition, x-show with animation) | Manual (Web Animations API, CSS classes) |
| Component Model | No (server-rendered partials) | Yes (x-data scopes, Alpine.data(), plugins) | Web Components (customElements.define()) |
| Backend Required? | Yes — htmx needs a server to return HTML | No — works with static HTML + small JS | No — works with everything |
| State Management | Server is the source of truth | Local (x-data), persisted (plugins, localStorage) | Manual (variables, localStorage, or libraries) |
| Learning Curve | Very Low (HTML attributes, no JS required) | Low (familiar to Vue devs, sprinkled in HTML) | Medium (need to know DOM APIs, no magic) |
When Each Approach Wins
htmx — Best for: Server-rendered web apps that need AJAX interactivity without a SPA framework. htmx shines when your backend (Django, Rails, Go, PHP) generates HTML and you want partial page updates, infinite scroll, optimistic UI, and real-time updates — all without writing JavaScript. Weak spot: Needs a server that returns HTML; cannot build a fully offline PWA; complex client-side state (drag-and-drop, rich text editing) still needs JS.
Alpine.js — Best for: Mostly static pages that need interactive sprinkles: dropdowns, modals, tabs, toggles, form validation, live search. Alpine is the modern replacement for jQuery — you get Vue-like reactivity with zero build step, dropped into any HTML page with a script tag. Weak spot: Not designed for SPAs; deeply nested components get unwieldy; no router; no build step means no TypeScript (without extra setup).
Vanilla JS — Best for: Developers who want zero dependencies and are comfortable with the platform. Modern browsers have excellent APIs: fetch(), Web Components, Web Animations, CSS custom properties, IntersectionObserver — you can build a lot without frameworks. Weak spot: You write more code; no magic means you re-implement things frameworks give for free; maintaining complex UI state manually gets tedious fast.
Decision Matrix
| Scenario | Best Choice | Why |
|---|---|---|
| Django/Rails/Phoenix app, need AJAX + SPA feel | htmx | Hypermedia fits server-rendered frameworks perfectly |
| Static marketing site, need dropdowns/tabs/modals | Alpine.js | Sprinkles of interactivity, zero build step |
| Zero-dependency policy, full control, small widget | Vanilla JS | No abstraction overhead, small surface area |
| Real-time dashboard (live updates via WebSocket) | htmx | hx-ext="ws" gives WebSocket-driven HTML swaps |
| Landing page with form validation + animations | Alpine.js | x-show + x-transition for animations, fetch for forms |
| Web Component library for distribution | Vanilla JS | Web Components are the standard; no deps = no conflicts |
Bottom line: Most web apps do not need React, Vue, or Svelte. htmx is the best choice for server-rendered apps that want SPA-like interactivity without JavaScript complexity. Alpine.js is the best choice for static pages that need interactive sprinkles — it's what jQuery wanted to be in 2026. Vanilla JS is the choice when you want zero dependencies and are comfortable writing to the platform. The common thread: all three approaches reject the SPA-everything default and pick the right amount of JavaScript for the job. See also: Alpine.js vs Vanilla JavaScript and Best JavaScript Frameworks.