Vanilla JS Is the Assembly Language of the Browser (And That's Why We Use It)
Gonzalo Monzón
Founder & Lead Architect
In February 2023, Alex Russell — who spent over a decade on the Google Chrome team — published "The Market for Lemons", a devastating critique of the JavaScript framework industry. His thesis: for a decade, "complexity merchants" sold heavy frameworks as the future of the web, while the resulting products were slower, more fragile, and worse for users. His conclusion: "We need to move our attention back to the folks who never gave up on semantic markup, CSS, and progressive enhancement." We are those folks. And we have numbers to prove it.
The Bloat Is Real (and Measurable)
In early 2024, Nikita Tonsky published "JavaScript Bloat in 2024", a methodical audit of how much JavaScript popular sites ship. The results are staggering:
| Site | What It Does | JavaScript Shipped |
|---|---|---|
| Tonsky's blog | Static content | 0.004 MB |
| Wikipedia | Static content + search | 0.2 MB |
| Gmail | Email client | 20 MB |
| Slack | Chat | 55 MB |
| Jira | Task management | 50 MB |
| Social + messaging | 31 MB | |
| Notion | Document editing | 16 MB |
| Vercel landing | Static landing page | 6 MB |
Slack ships 55 MB of JavaScript — the size of the original Quake 1 — for a chat app. Meanwhile, Tonsky's blog delivers the same core value (showing text to humans) with 0.004 MB. That's a 13,750x difference in code for fundamentally similar output: text on a screen.
As Tonsky put it: "Call me old-fashioned, but I firmly believe content should outweigh code size. If you are writing a blog post for 10K characters, you don't need 1000× more JavaScript to render it."
The Assembly Analogy
Vanilla JavaScript and pure CSS are to the browser what assembly language is to the CPU. They are the native instruction set. Everything else — React, Vue, Svelte, Tailwind, Sass — compiles down to them eventually. Every useState becomes a closure. Every className="flex items-center" becomes a CSS rule. Every JSX expression becomes a document.createElement call.
When you understand the low-level primitives, you gain three superpowers:
- You know what's actually happening. When something breaks, you don't debug the framework — you debug the browser. DevTools speaks vanilla JS and CSS, not React or Vue
- You can evaluate frameworks honestly. You know what they're abstracting, what they cost, and whether that cost is justified for your use case
- You can build without them. When a framework adds overhead that doesn't serve the user, you have the option to simply... not use it
This doesn't mean frameworks are bad. It means knowing when not to use one is the skill that separates engineers from framework operators.
The Market for Lemons: A Decade Lost
Alex Russell's critique is worth reading in full, but the key argument is economic. When sellers have more information than buyers, low-quality products dominate the market — Akerlof's "lemons" theory. Applied to frontend:
"Partisans for slow, complex frameworks have successfully marketed lemons as the hot new thing, despite the pervasive failures in their wake, crowding out higher-quality options in the process."
— Alex Russell, The Market for Lemons (2023)
The frameworks were born at Facebook and Google — companies with dedicated performance teams, ship gates, latency budgets, and hundreds of engineers to manage complexity. When transplanted to a typical team of 3-10 developers, these tools became expensive duds: slow to load, fragile to maintain, and requiring an entire ecosystem of abstractions (SSR, code splitting, hydration, streaming) to mitigate problems they themselves created.
Jeremy Keith, one of the most respected voices in web standards, put it bluntly in November 2023: "At this point React is legacy technology, like Angular. Lots of people are still using it, but nobody can quite remember why."
The Great Gaslighting
Jared White of The Spicy Web captured what many of us felt for years:
"We were told writing apps with an HTML-first, SSR-first, progressively enhanced mindset was outdated and bad for users. That was a lie. We were told writing apps completely using frontend JavaScript would make our lives easier. That also was a lie."
His core point is devastating: "JavaScript is not required to build a simple web site. HTML, CSS, and JavaScript. Not JavaScript, JavaScript, and JavaScript."
The web is polyglot by design. HTTP doesn't care what language generates the HTML. The browser doesn't care what tool wrote the CSS. The user doesn't care about your DX — they care about speed, reliability, and whether the damn button works.
Web Components Will Outlive Your Framework
Jake Lazaroff wrote one of the most important posts of 2023 about this theme. His argument: if you want your work to last, build on web standards, not framework APIs.
"I've been building on the web for almost 20 years. That's long enough to witness the birth, rise and fall of jQuery. Backbone burst onto the scene and was quickly replaced with AngularJS, which was replaced with React, which has been around for only half that time and has still gone through like five different ways to write components."
The original Space Jam website from 1996 still renders perfectly in modern browsers. The first website ever created — closer to the formation of the Beatles than to today — still works. Meanwhile, React projects from 2018 often won't compile without major dependency surgery.
Standards last. Frameworks don't. Choose accordingly.
The htmx Case Study: 67% Less Code, 50% Faster
Theory is fine, but what about real-world results? At DjangoCon 2022, Contexte presented their port from React to htmx. The numbers speak for themselves:
| Metric | React | After (htmx) | Change |
|---|---|---|---|
| Codebase size | 21,500 LOC | 7,200 LOC | -67% |
| JS dependencies | 255 | 9 | -96% |
| Build time | 40 seconds | 5 seconds | -88% |
| Time to interactive | 2-6 seconds | 1-2 seconds | -50-60% |
| Memory usage | 75 MB | 45 MB | -46% |
But the most revealing change was organizational: the entire team became full-stack developers. With React, there was a hard split between frontend and backend. Without it, every developer could own a feature end-to-end. Less coordination, faster shipping, happier engineers.
Our Approach: Know the Low Level, Choose the Right Level
We're not framework haters. We're not building everything in vanilla JS out of dogma. We're engineers who understand the low-level primitives and choose the right abstraction for each job. Here's how that plays out across our stack:
Pure Vanilla JS + CSS (zero dependencies)
- cookie-consent.js — Our entire cookie consent system: IIFE, self-contained CSS injection, localStorage, bilingual UI, analytics gating. 4KB total, zero dependencies. A React equivalent with a UI library would be 50-200KB minimum
- Perspectiva Studio — ~15 modules (audio, video, chat, embeddings, publications, model management) in pure vanilla JS. No build step. Open
index.htmlin a browser and it works. Has worked for years without a single dependency update - Client landing pages (Vall, NutriNen, etc.) — Static HTML, pure CSS, Alpine.js for sprinkles of interactivity. Load in under 1 second on 3G
Astro (SSG — static site generation)
- cadenceslab.com — This very site. Astro generates static HTML at build time. The blog you're reading is a pre-rendered HTML file. Zero JavaScript shipped to the client for content pages. Astro earns its place because it does one thing superbly: turn components into static HTML and get out of the way
- GoViajes, GoStorm — Travel and event platforms where the content is mostly static but the data model benefits from Astro's collections and i18n routing
React (interactive islands)
- Cadences platform — The main product is a complex interactive app: real-time project management, AI chat, voice integration, workflow builders, data explorers. React earns its place here because the UI is genuinely stateful, interactive, and complex
- Blog interactive components — When a blog post needs a live demo or interactive widget, we use React as an Astro island: it hydrates only when visible, ships JS only for that component, and the surrounding page remains static HTML
The decision tree is simple:
Is it static content? → HTML + CSS. Done.
Needs a sprinkle of interactivity? → Vanilla JS or Alpine.js
Needs SSG with routing/i18n? → Astro
Genuinely complex interactive UI? → React (as island or SPA)
Could it be simpler? → Go back to step 1
What We Actually Ship (By the Numbers)
| Product | Tech | JS Shipped to Client | Why This Choice |
|---|---|---|---|
| cadenceslab.com | Astro + islands | ~15KB (Alpine + consent) | Content site, needs zero client JS for content |
| Cookie consent | Vanilla JS | 4KB | Self-contained, no dependencies to maintain |
| Perspectiva Studio | Vanilla JS | ~80KB (15 modules) | No build step, works forever |
| Client landings | HTML + CSS + Alpine | ~12KB | Maximum performance, minimum complexity |
| Cadences app | React | ~350KB | Complex interactive UI justifies the cost |
Compare our content site (15KB) to Vercel's landing page (6MB). That's a 400x difference. Our entire cookie consent system is smaller than the average React useState tutorial page.
Pure CSS: The Forgotten Superpower
The same principle applies to CSS. While the industry was busy inventing CSS-in-JS, CSS Modules, Styled Components, Emotion, and seventeen flavors of utility classes, the browser was quietly shipping features that make most of those tools unnecessary:
- CSS Custom Properties — Native variables with cascade inheritance. No build step needed
- CSS Grid + Flexbox — Layout solved natively. No Bootstrap grid, no flexbox utilities
:has()selector — The "parent selector" we waited 20 years for. Now you can style based on children without a single line of JS@containerqueries — Component-level responsive design, natively@layer— Native cascade management. No more!importantwars- Nesting — Native CSS nesting, no Sass required
color-mix(),oklch()— Advanced color manipulation without preprocessors
Our client pages use pure CSS with custom properties for theming. Each brand (Vall Inmobiliaria, NutriNen, GoViajes) gets its own CSS file with a custom property palette — no Tailwind config, no build step, no PostCSS. Change --brand-primary and the entire site rebrands. It's CSS doing what CSS was designed to do.
The Longevity Argument
Jake Lazaroff's point about longevity deserves repetition. Our Perspectiva Studio modules — written in vanilla JS years ago — still work perfectly today. No npm audit alerts. No breaking changes from dependency updates. No "this project uses React 16 and needs to be migrated to 18." Open the HTML file, it works.
TypeScript is wonderful, but even it has breaking changes in every release. As Lazaroff noted: "the last 15 versions of TypeScript have had breaking changes." For long-lived code that you don't plan to actively maintain, vanilla JS is the safest bet. It's the one technology guaranteed not to break, because the browser makers have committed to never breaking the web.
The first website, built in 1991, still works. Can you say the same about your React app from 2019?
Key Takeaways
1. Vanilla JS and pure CSS are the browser's native instruction set. Everything else compiles to them. Understanding them deeply isn't "old school" — it's the foundation that lets you evaluate and choose (or refuse) every other tool. The engineers who know the low level always have the advantage.
2. The framework tax is real and measurable. 55MB of JS for a chat app. 20MB for an email client. 6MB for a landing page. The "complexity merchants" sold DX improvements that degraded UX. As Alex Russell documented, the industry lost a decade to the market for lemons.
3. We're not anti-framework — we're anti-default-framework. React powers our Cadences platform because complex interactive UIs genuinely benefit from it. Astro generates this blog because static site generation is genuinely useful. But cookie consent doesn't need React. A landing page doesn't need Next.js. The right tool for the job is sometimes no tool at all.
4. Web standards outlive everything. jQuery came and went. AngularJS came and went. React's had five different component patterns in 10 years. HTML, CSS, and vanilla JS from 1996 still work perfectly. Build on the substrate, not on the abstraction layer that'll be deprecated next year.
5. The best DX is invisible infrastructure. Our cookie-consent.js has zero dependencies, zero build steps, and hasn't needed an update since it was written. Perspectiva Studio's 15 modules work by opening an HTML file. That's not tech debt — that's tech freedom. The less your code depends on, the less it can break.
Tags
About the Author
Gonzalo Monzón
Founder & Lead Architect
Gonzalo Monzón is a Senior Solutions Architect & AI Engineer with over 26 years building mission-critical systems in Healthcare, Industrial Automation, and enterprise AI. Founder of Cadences Lab, he specializes in bridging legacy infrastructure with cutting-edge technology.
Related Articles
Edge Computing: Why We Bet Everything on Cloudflare (And What $65/Month Gets You)
No servers, no containers, no Kubernetes. We run 14+ interconnected products on 9 Cloudflare products — Workers, D1, R2, Durable Objects, Pages, KV, Vectorize, Workers AI and WAF. $65/month for what would cost $400-600 on AWS. Here's the full architecture.
Synapse Studio: A 2D Virtual Office Where AI Agents Do the Real Work
We built a SimTower-style animated office where AI agents with multimodal capabilities — vision, image generation, web search, iterative image evolution — collaborate on real tasks. Zero dependencies, pure Vanilla JS, running on Cloudflare.
Perspectiva Studio: 19,000 Lines of Vanilla JS That Create Audiobooks, Blogs, and AI Coach Sessions
We built a full content creation engine — audiobooks with 15+ ElevenLabs voices, blog articles with AI-generated images from 5 providers, PDF documents, and real-time AI Coach sessions — all in zero-dependency Vanilla JS running on Cloudflare.