This content originally appeared on Go Make Things and was authored by Go Make Things
I’ve worked on so many projects recently that were more complicated than they needed to be because they used JavaScript to generate HTML.
JavaScript is…
- Slower to load
- Slower to run
- More prone to breaking
- Harder to read and reason about
- Doesn’t actually look like the final output
It’s inferior to just using HTML in nearly every way.
I’m not saying never use JavaScript, though. I think JS is great at augmenting and enhancing what’s already there, and adding interactivity that cannot (yet) but handled with HTML.
Let’s look at two examples…
Submitting a form
I see this a lot in React and JSX.
Every input in a form has an input
listener on it. Any changes to that input update a state property. That property is used to set the value of the input, creating this weird circular logic.
(This approach is called “controlled inputs” in React-land, and some devs are slowly moving away from it, finally.)
The form submit is often also tied to clicking a <button>
rather than submitting a form, meaning that hitting enter on an input won’t submit the form. This removes a native accessibility feature.
function Login () {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
function handleSubmit () {
if (!username || !password) {
// Show error message
return;
}
fetch('/login', {
method: 'POST',
body: JSON.stringify({
username,
password
}),
});
}
return (
<form onSubmit={event => event.preventDefault()}>
<label for="username">Username</label>
<input
id="username"
type="text"
onInput={event => setUsername(event.value)}
value={username}
/>
<label for="password">Password</label>
<input
id="password"
type="password"
onInput={event => setPassword(event.value)}
value={password}
/>
<button onClick={handleSubmit}>Submit</button>
</form>
);
}
Here’s that same setup with HTML…
<form action="/login" method="POST">
<label for="username">Username</label>
<input
id="username"
type="text"
required
/>
<label for="password">Password</label>
<input
id="password"
type="password"
required
/>
<button>Submit</button>
</form>
And then you can enhance it with just a touch of JavaScript…
const form = document.querySelector('[action*="/login"]');
form.addEventListener('submit', event => {
event.preventDefault();
const data = new FormData(form);
const body = JSON.stringify(Object.fromEntries(data));
fetch('/login', {
method: 'POST',
body
});
});
Hell, you can even do this in React if you want!
function Login () {
function handleSubmit (event) {
event.preventDefault();
const data = new FormData(event.target);
const body = JSON.stringify(Object.fromEntries(data));
fetch('/login', {
method: 'POST',
body
});
}
return (
<form onSubmit={handleSubmit}>
<label for="username">Username</label>
<input
id="username"
type="text"
required
/>
<label for="password">Password</label>
<input
id="password"
type="password"
required
/>
<button>Submit</button>
</form>
);
}
API responses
Another area where you can lean a lot more heavily on HTML is API responses.
Let’s say you have a <table>
that gets generated based on some data that’s specific to the user or some selections that have been made in a <form>
.
In most modern apps, that means getting back some JSON, and generating a <table>
from it.
const app = document.querySelector('#app');
const request = await fetch('/my-wizards');
const response = await request.json();
app.innerHTML =
`<table>
<thead>
<tr>
<th>Name</th>
<th>Location</th>
<th>Powers</th>
</tr>
</thead>
<tbody>
${response.wizards.map(wizard => {
const {name, location, powers} = wizard;
const row =
`<tr>
<td>${name}</td>
<td>${location}</td>
<td>${powers}</td>
</tr>`;
return row;
}).join('')}
</tbody>
</table>`;
But if a server has to do the work of getting that information and sending it back to you anyways, it could also just send the <table>
HTML, which you could then render into the UI.
const app = document.querySelector('#app');
const request = await fetch('/my-wizards');
const response = await request.text();
app.innerHTML = response;
There are workflow changes
This, of course, changes the workflow of building apps quite a bit.
A lot of work shifts to the backend that in today’s apps is handled with client-side code. But… that’s a good thing?
It means faster, simpler apps that behave more predictably and reliably.
Like this? A Lean Web Club membership is the best way to support my work and help me create more free content.
This content originally appeared on Go Make Things and was authored by Go Make Things

Go Make Things | Sciencx (2025-09-10T14:30:00+00:00) Just use HTML. Retrieved from https://www.scien.cx/2025/09/10/just-use-html/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.