The Native Web Way
A white paper on building closer to the browser. What frameworks cost, what the platform now does on its own, and a production site you can measure yourself.
A white paper, version 1.2, October 2026. Masum Billah, Brand and Business Systems Architect, founder of Digitalizen, Dhaka and Manila.
Abstract
Ten years ago, a JavaScript framework was the sensible answer to a real problem. Browsers disagreed with each other, the DOM was awkward to work with, and a library that smoothed all of that over saved weeks of work. The browsers have since caught up. The frameworks stayed, and so did their cost: more code sent to every visitor, more packages to trust, more work to keep it all current.
The Native Web Way, NWW for short, is a default rather than a rule. Start from what the browser already does well, which is parsing HTML, laying out CSS, and fetching JSON. Add a framework only where a piece of the interface genuinely holds a lot of changing state. This paper sets out the argument, shows two patterns, compares published industry data with a site I run, and is plain about where the approach does not fit.
A note on evidence. Most architecture papers ask you to trust their numbers. The case study in this one is billah.dev, the site you are reading, and every figure about it can be checked from your own browser in a couple of minutes.
1. How we got here
Frameworks earned their place. Around 2013, building a rich interface meant fighting browser differences, writing a lot of manual DOM code, and inventing your own way to organise components. React and the ecosystem around it, and later Next.js, Nuxt and Remix, gave teams a shared model and a lot of productivity.
The platform kept moving underneath them. Custom Elements, the Fetch API, Declarative Shadow DOM, native form validation, lazy loading and priority hints are all built in now. Much of what a framework was added for, the browser handles directly.
Yet the default has not changed. A new project still tends to start with a framework, because that is what the team knows and what the tutorials assume. I call the result architectural debt: complexity a system keeps paying for long after the reason for it has gone.
2. What the default costs
2.1 Work the browser does twice
React and libraries like it keep their own copy of the page in memory, a virtual DOM, and compare versions of it to decide what to change. Not every framework does this. Svelte, Solid and Qwik take different routes. But the React model is the one most production sites run, and it carries three costs.
The page exists twice, once in the browser and once in JavaScript. A server rendered page looks ready before it is, because nothing responds to a tap until the scripts have downloaded, run, and reattached themselves to the HTML. This step is called hydration, and on a slow phone it is the gap between seeing a button and being able to press it. And small state changes can trigger re-renders that keep the processor and the garbage collector busy, which shows up as sluggish response to input.
2.2 Code that has to travel
According to the HTTP Archive Web Almanac, the median mobile page in 2024 loaded 558 KB of JavaScript across 22 requests, and roughly 44 percent of those bytes went unused during page load. Two things follow from that.
Every package in a dependency tree is code someone else wrote that now runs on your visitor's device. Supply chain attacks through npm packages are no longer rare news.
On a phone with a busy connection, downloading, parsing and compiling all of that script is often the slowest part of opening a page, slower than the server's reply. A fast backend does not help if the browser is still busy with JavaScript.
3. Browser, HTML, JSON
NWW rests on three things the browser engines, Blink, WebKit and Gecko, have spent two decades optimising.
The browser is the runtime. It parses HTML as it streams in, computes layout natively, and runs animations on transform and opacity on the compositor, without touching the main thread. NWW lets the engine do that work instead of rebuilding it in JavaScript.
HTML carries structure and meaning, and it now does a lot more than it used to. Custom Elements and Declarative Shadow DOM give you components. Forms validate themselves. Images load lazily with one attribute. A link or a button already knows how to be clicked, focused and announced to a screen reader.
JSON moves data. A plain fetch call returns plain data, the page updates exactly the part that changed, and the response can be cached like any other file. There is no client side store to keep in sync with the server.
4. What the numbers say
Comparing one small site with the median of the whole web is not a fair fight, and I do not present it as one. A portfolio is lighter than a shop. The point of the table is narrower: it shows how far from the norm a content site can sit when it does not start from a framework, using figures anyone can reproduce.
| Measure | Median mobile page | billah.dev homepage |
|---|---|---|
| JavaScript transferred | 558 KB (2024) | 0 KB of executable script |
| JavaScript requests | 22 (2024) | 0 |
| Unused JavaScript at load | about 44 percent of what was sent (2024) | none to measure |
| Total page weight | about 2.6 MB (2025) | about 55 KB, fonts and favicon included |
The median figures come from the Web Almanac chapters listed in the references. The billah.dev figures come from the production build: the HTML compresses to about 8 KB with its CSS inlined, plus two font files, one small image and the favicon. The page does carry two script tags, but both hold data rather than code, one for search engine structured data and one for the browser's speculative prefetch rules. Neither runs anything.
I have left out timing figures such as Time to Interactive and Interaction to Next Paint. They depend heavily on the device and the network, and a single number from my desk would mean little on yours. PageSpeed Insights will measure them for you in under a minute, and the link is in the references.
5. Two patterns
5.1 A component without a library
A Custom Element can fetch its own data and render it with nothing imported. Two details matter here. The text from the server goes in through textContent, so a name containing HTML stays as text and cannot run as code. And a failed request leaves the user a message instead of a spinner that never stops.
class UserProfileCard extends HTMLElement {
async connectedCallback() {
const id = encodeURIComponent(this.dataset.userId);
this.textContent = "Loading";
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(res.status);
const user = await res.json();
const name = document.createElement("h3");
name.textContent = user.name;
const email = document.createElement("p");
email.textContent = user.email;
const card = document.createElement("div");
card.className = "user-card";
card.append(name, email);
this.replaceChildren(card);
} catch {
this.textContent = "This profile could not be loaded.";
}
}
}
customElements.define("user-profile-card", UserProfileCard);
Where the data is known at build time, it is better still to send the card already rendered in the HTML and let the element only add behaviour. Then the page works even before any script arrives.
5.2 One listener for many buttons
Instead of attaching a handler to every row in a table, attach one to the table and let events bubble up to it. Rows added later work without any extra wiring.
document.querySelector("#data-table").addEventListener("click", (event) => {
const target = event.target.closest("[data-action]");
if (!target) return;
if (target.dataset.action === "delete") {
deleteRecord(target.dataset.id);
}
});
6. Security and the cost of ownership
6.1 Security
A smaller dependency tree is a smaller list of people whose mistakes can end up running in your visitor's browser. That is the plain case for it.
The second case is the content security policy. A strict policy refuses any script the server did not explicitly approve for that response, which is one of the strongest defences against injected code. It is possible with a framework, but it gets harder with every inline script and third party tag the framework or its plugins add. With almost no script on the page, a strict policy is easy to keep. billah.dev issues a fresh nonce with every request. I wrote about the one surprise that caused, with conditional requests, in a separate piece listed in the references.
6.2 Cost over the years
A site that is mostly finished HTML does not need a cluster of Node servers rendering it on every request. It can be served from an edge network or static storage, often within a free tier, with a small worker or a lightweight backend handling the few things that are genuinely dynamic.
It also ages well. HTML, CSS and plain JavaScript written today should still run in browsers a decade from now. Framework code tends to need a migration every couple of major versions, and that work produces nothing a customer can see.
7. Moving an existing site
- Measure first. The Coverage and Performance panels in Chrome DevTools show which scripts are loaded, how much of each is used, and what blocks the first interaction.
- Turn the static parts back into HTML. Headers, footers, article bodies and product descriptions rarely need JavaScript. Render them on the server or at build time, and leave only the interactive parts as islands.
- Rebuild shared UI as Custom Elements. A button, a modal or a tab set written as a native element works in any page and with any framework, which also makes the move gradual rather than a rewrite.
- Let the server speak JSON. When endpoints return plain data, a few lines of native script can update the page without a client side framework in the middle.
8. Where it does not fit
This approach has real costs, and a paper that hid them would not be worth reading.
Frameworks come with mature tools for routing, state, testing and team conventions. Going native means choosing or building those pieces yourself, and that takes judgement.
A team that knows React well is productive in React. Retraining has a cost, and so does hiring for a less common skill set.
Some applications genuinely are mostly state: a collaborative editor, a trading screen, a complex dashboard. A reactive framework earns its weight there, ideally contained to the parts of the page that need it.
That is why I call NWW a default and not a prohibition. For client work I still use React, Next.js and Express when the job calls for them. But when the content allows it, and for most business sites it does, building on the native platform gives the visitor more and costs the owner less.
9. Case study: billah.dev
A claim about architecture is only as good as a system you can inspect. This section describes one.
9.1 What it is built on
billah.dev is the portfolio and writing site for my practice in web development, performance marketing and AI automation.
| Principle | How it shows up |
|---|---|
| No framework for content | Pages are written as Markdown and JSON, and a build script of a few hundred lines turns them into finished HTML |
| Framework only where state lives | This site has none. Its only development dependency is the Cloudflare deploy tool |
| Served from the edge | Cloudflare Workers, deployed as a single unit |
| Almost no JavaScript | The homepage runs no script at all |
| Strict security policy | A new nonce on every response, no unsafe-inline |
The servers that run my agency's own services are a separate system from this site, and the same thinking applies to them. They have run five production services for more than three years without a rebuild.
9.2 Checking it yourself
Run PageSpeed Insights against billah.dev, using the link in the references.
Open the network panel in your browser's developer tools and reload the homepage. You will see the HTML, two fonts, one small image and the favicon. No framework runtime, analytics library or advertising tag loads.
View the page source. The two script tags hold JSON data, not code.
9.3 What it shows and what it does not
It does not show that NWW suits every application. Section 8 already says it does not. What it shows is that a content heavy site, the kind that most often gets built on a full server rendering framework by habit, can run commercially on HTML, CSS and a little JSON, and that the results hold up in production rather than only in a lab.
10. Conclusion
None of this asks anyone to give up modern web development. The browser is the most capable runtime most of us will ever deploy to, and it gets better every year without us shipping a byte. The less we stack on top of it, the faster our pages open, the fewer things can break, and the longer the work lasts.
References
- WHATWG, HTML Living Standard: Custom elements
- web.dev: Interaction to Next Paint
- HTTP Archive, Web Almanac 2024: JavaScript
- HTTP Archive, Web Almanac 2025: Page Weight
- Google PageSpeed Insights: billah.dev, measured live
- Masum Billah: The website that costs nothing to run
- Masum Billah: The refresh that stripped my own website
About the author
Masum Billah, known online as billahdotdev, is a Brand and Business Systems Architect working from Dhaka and Manila, and the founder of Digitalizen, a performance marketing and web systems agency. For nine years he has built and run the systems behind client businesses: websites, ad infrastructure, tracking, AI sales automation and self-hosted servers. He has handled 284 clients personally and more than 600 through the agency. He holds certifications in full stack development from IAC and BUET, in AI and automation from the National Information Society Agency of South Korea, in marketing from AMA in the Philippines, and Full Stack Open from the University of Helsinki.
Write to masum@billah.dev, or find him on GitHub.