Engineering
Ship Less JavaScript
Somewhere along the way, frontend engineering developed a default: whatever the problem, the answer involves more JavaScript. Need a carousel? Library. Smooth scrolling? Library. A date? Sixty kilobytes, historically. The median page now ships hundreds of kilobytes of compressed script, which decompresses, parses, and executes on phones far worse than the ones we develop on, all to render what is usually text, images, and a form.
Here is the thing the ecosystem is finally admitting in 2023, with server components going mainstream and every framework racing to ship less to the client: most of that JavaScript was never necessary. The platform caught up years ago. We just stopped checking.
The platform can do that now
A partial list of things we shipped dependencies for in 2019 that are now one line of platform:
- Lazy-loading images.
loading="lazy". That is the whole implementation. The intersection observer boilerplate, and certainly the library wrapping it, can go. - Native dialogs. The
<dialog>element, with focus trapping and a real top layer, is supported in every current major browser as of last year. We deleted a modal dependency from two projects this spring. - Accordion and disclosure.
<details>and<summary>have been fine for years. Style them and move on. - Smooth scrolling, sticky positioning, aspect ratios, form validation. CSS. All of it.
scroll-behavior,position: sticky,aspect-ratio, and the constraint validation API cover the overwhelming majority of real use.
And the one that still surprises designers in reviews: scroll-driven reveal animations, the single most requested marketing-site effect, need about ten lines:
const observer = new IntersectionObserver((entries) => {
for (const e of entries) {
if (e.isIntersecting) e.target.classList.add("in-view");
}
}, { threshold: 0.2 });
document.querySelectorAll("[data-reveal]").forEach((el) => observer.observe(el));
Pair with a CSS transition and you have replaced an animation library on most brochure sites.
Audit by asking rude questions
Deleting JavaScript is mostly a social exercise, so our bundle audits ask blunt questions of every dependency:
- What would this cost to write ourselves? (The honest answer for many utility libraries: an afternoon.)
- Does this run before first interaction, and if so, why?
- Is this polyfilling a browser we no longer support? Check your actual analytics, not your 2019 assumptions. The long tail of ancient browsers most teams defensively support has, for most audiences, simply left.
- Who added this, and do they still believe in it?
On our last client audit this process removed 38 percent of client-side JavaScript with zero functional change. Nobody had decided to ship that weight. It had accreted, dependency by reasonable dependency.
Frameworks are not the enemy, defaults are
This is not an anti-React post; we ship React happily and often. The problem is defaulting to client-side everything for sites that are fundamentally documents. The current generation of tools finally makes the right thing easy: server components render the static majority with no client cost, and islands-style architectures let a page be 95 percent HTML with interactivity exactly where it earns its bytes. The technology argument is over. What remains is habit.
So the practice we hold: JavaScript is a budget line, every interactive element must justify its hydration, and the default answer to "how do we build this?" is HTML and CSS until proven otherwise. Your users' phones are worse than yours, their networks are worse than yours, and none of them have ever once wished a website shipped more script. Delete generously. The platform will catch you.
Building something this could apply to?
We take on a small number of flagship projects each quarter.
Start a project