Skip to main content
HTML-First vs React/Next.js: When You Don't Need a JavaScript Framework

HTML-First vs React/Next.js: When You Don't Need a JavaScript Framework

· 16 min read
Practical guides for developers

A UK utility company hired contractors to build a React app for a public form. The app was pulled three days after launch due to customer complaints. A developer then rebuilt it as an HTML-first Astro site (no React, no single-page app, each form step its own page). When the new version launched, the number of people completing the form doubled overnight. The developer noted that javascript-based analytics had been hiding the true bounce rate. The React version was silently failing users who never appeared in the data.

React is the default choice for many web projects. The default has a cost, though, and it is not always the right choice. This article shows what HTML-first and React/Next.js each provide, what they cost, and how to decide which fits your project.

Quick comparison

HTML-FIRST VS REACT/NEXT.JS · QUICK COMPARISONEight dimensions side by sideDIMENSIONHTML-FirstReact / Next.jsJS dependencyNone requiredRequired (Next.js SSRreduces exposure)SetupOpen a file inany editorNode 20.9+, npm install,dev serverBundle overheadZero~61 KB gzip for Reactruntime + app codeFormsNative browser validation+ FormDataLibrary (React Hook Form,Zod) or customRoutingFile structure +<a> tagsFile-based App Routeror React RouterState managementNot needed forsimple sitesuseState, Context,or ReduxSEOExcellent (HTML renderedby default)Excellent with SSR/SSG(Next.js)Best forContent sites, forms,public servicesSPAs, dashboards,real-time apps

What HTML-first means

HTML-first means the page works correctly with no JavaScript loaded. JavaScript is added only where it enhances the experience. The core function never requires it. A contact form submits via a plain POST. A multi-step wizard redirects between pages using server-side sessions. If the JavaScript fails to load or execute, the form still works.

This is how the GOV.UK platform was designed: "simple HTML... lightweight and will work even on rubbish browsers. They have to. This is for everyone." HTML5 provides native validation attributes (required, type="email", minlength) that the browser enforces without any library. A form with these attributes delivers correct validation behavior in under 1 KB.

<form method="POST" action="/contact">
<label for="email">Email</label>
<input type="email" id="email" name="email" required />
<label for="message">Message</label>
<textarea id="message" name="message" required minlength="10"></textarea>
<button type="submit">Send</button>
</form>

What React and Next.js add

React is a JavaScript library for building interactive user interfaces. It is designed for UI that has state (data that multiple components need to read and update). React takes ownership of the DOM. In the words of the React docs: "you don't get to deal with the DOM directly. I have a virtual DOM and I deal with that." This abstraction is what makes complex, reactive UIs manageable.

Next.js is a React framework that adds routing, server-side rendering, image optimisation, and API routes in a single project. It also handles bundling and compilation automatically. The practical cost is a JS runtime the browser must download and execute. A production Vite + React 18 build for a contact form runs to 60.7 KB gzip before any app-specific code. A misconfigured React app can make that form completely inaccessible to users on slow connections. The utility developer found this out directly. As they noted after the rebuild, "your javascript-based analytics package doesn't see the users you are bouncing because of javascript failures."

When HTML-first is the right choice

HTML-first is the better fit when:

  • The site is primarily content (a blog, documentation, a landing page, a marketing site)
  • The main interaction is a form wizard (application, sign-up, quote request), where server-side sessions and POST redirects are simpler and more reliable than client-side state
  • You need the widest possible device and browser support for public services or accessibility-critical applications
  • The team is small or solo and you do not want to maintain a Node.js server
  • You want zero JavaScript on the page by default for privacy, performance, or simplicity
  • The app is a few pages with no real-time state

The utility case study illustrates this directly. The requirements were "it should be possible to complete the form without javascript" and "it should be possible to complete the form on outdated and crap web browsers." React imposed complexity (loading spinners, global state, localStorage image upload with a 5 MB limit) without providing anything those requirements called for. Chris Coyier made the general point clearly. "A blog, for example, probably has none of the problems and fits none of the scenarios that would make React a good fit. And because it's not a good fit, it's probably a bad fit, because it introduces complicated technology and dependencies for something that doesn't call for it."

When React or Next.js is the right choice

React and Next.js earn their overhead when:

  • The UI has complex state, where multiple components need to read and write the same data (shopping cart, dashboard filters, user session across views)
  • You need real-time updates from multiple sources (chat, live scores, collaborative editors)
  • The team is large and you need component discipline to prevent spaghetti code (React's module structure enforces this)
  • You want a full-stack project with routing, API endpoints, auth, and SSR in one place (Next.js App Router)
  • You need fine-grained caching and incremental static regeneration
  • You are building a mobile app with React Native (shared codebase with the web version)

Stripe, Linear, and Notion are good examples. All three have UIs with nested state shared across dozens of interactive components. The complexity is real, and React is the right tool for it. React earns its overhead when your project has the problems it solves.

Building the same feature both ways

To compare directly, here is a contact form that collects email and message, submits via AJAX, and shows a status message. No page refresh. Both versions produce identical user-facing behaviour.

The HTML-first version

<form id="contact-form">
<label for="email">Email</label>
<input type="email" id="email" name="email" required />
<label for="message">Message</label>
<textarea id="message" name="message" required minlength="10"></textarea>
<button type="submit">Send</button>
<p id="status" aria-live="polite"></p>
</form>

<script>
document.getElementById('contact-form').addEventListener('submit', async (e) => {
e.preventDefault();
const data = new FormData(e.target);
const res = await fetch('/api/contact', { method: 'POST', body: data });
document.getElementById('status').textContent = res.ok ? 'Sent!' : 'Error — try again.';
});
</script>

A contact form using native FormData and fetch, with no libraries and no build step.

This gives you native browser validation, progressive enhancement (the form works without the script block), no dependencies, and no build step. The total JavaScript is approximately 200 bytes.

The React version

import { useState } from 'react';

export default function ContactForm() {
const [status, setStatus] = useState('');

async function handleSubmit(e) {
e.preventDefault();
const data = new FormData(e.target);
const res = await fetch('/api/contact', { method: 'POST', body: data });
setStatus(res.ok ? 'Sent!' : 'Error — try again.');
}

return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input type="email" id="email" name="email" required />
<label htmlFor="message">Message</label>
<textarea id="message" name="message" required minLength={10} />
<button type="submit">Send</button>
{status && <p aria-live="polite">{status}</p>}
</form>
);
}

The same form as a React component. The logic is identical (both use FormData and fetch). The difference is what you pay to run it. A React app requires Node.js 20.9+, npm, a bundler, and a 60.7 KB gzip React runtime. For a standalone contact form, that is overhead to do something the browser already knows how to do. The React version pays off when this form is one of dozens of interactive components sharing state across a page.

How to decide

Ask three questions about your project:

HTML-FIRST VS REACT/NEXT.JS · DECISION FRAMEWORKThree questions to choose the right toolQUESTIONIf yesIf noDoes the UI have state that multiplecomponents need to read and update?ReactHTML-firstDo you need real-time data —chat, live feeds, collaborative editing?React/Next.jsHTML-firstWill many developers maintain this?Do you need component discipline?ReactHTML-first

If all three answers are no, HTML-first is almost certainly the simpler, faster, and more accessible choice. If any answer is yes, React earns its overhead.

The utility developer put it well. "I have nothing against heavily client-side applications, in their place. But this is just a big form — it's not showing real-time data." Start with HTML and add a framework when the problem actually demands one.

About the author

ST
Simple Tech GuidesPractical guides for developers

Simple Tech Guides publishes practical, developer-focused content on frameworks, tools, and platforms.