The Default Reflex Is Worth Questioning

Open a new project and the first question most developers ask is which framework, not whether one. That reflex made sense in 2013, when the DOM API was a minefield and IE quirks demanded an abstraction layer. It makes less sense today.

Modern browsers ship with querySelector, fetch, the Web Animations API, custom elements, and <dialog> — a native modal that handles focus trapping and accessibility out of the box. The platform you're targeting is genuinely capable. The question worth asking before installing anything is: what, exactly, will a framework add here?

For a marketing page, a documentation site, a simple dashboard, or a tool with a handful of interactive controls, the honest answer is often: routing you don't need, a virtual DOM for updates that happen twice a day, and a build pipeline you'll spend an afternoon configuring.

What "Plain" Actually Looks Like

"No framework" doesn't mean 1998 spaghetti. A well-organised vanilla project uses ES modules natively (browsers have supported them since around 2017), imports utilities from small focused packages, and keeps state as close to the DOM as possible. You can write clean, maintainable code without a component model — you just structure it yourself.

js.js
// native module, no build step required
import { formatDate } from './utils/date.js';

const banner = document.querySelector('#event-banner');
banner.textContent = `Next event: ${formatDate(new Date())}`;

That's a real, shippable file. No compilation, no node_modules for the runtime, no hydration mismatch. For straightforward use cases, this is fast to write, fast to load, and easy for the next person to read.

Where things genuinely get complex — rich interactivity, shared state across many components, server-rendering requirements — a framework pays for itself quickly. Reach for one then. The mistake is reaching for it before that threshold arrives, then spending the project managing the abstraction rather than building the thing.

The Skill That Transfers

There's a practical argument beyond bundle size: understanding what the browser actually does makes you better at every framework you'll ever use. The developer who knows that React's useEffect cleanup mirrors removeEventListener, or that Svelte's reactivity compiles down to direct DOM mutations, debugs faster and writes less defensive code.

Starting with less isn't a form of purism. It's how you stay calibrated — so that when a framework does arrive in a project, you chose it, rather than inherited it by default.