In today’s developer ecosystem, modern web development usually comes with some baggage. Starting a new project often involves using some combination of a build tool (like Vite or Webpack), a package manager (like npm or yarn), and a framework (like React, Vue, or Svelte). While these tools provide powerful features and a great developer experience, they’re not always needed for every project.
If you’re building something small to medium-sized, pulling in a full React setup with a build step can feel like overkill. Moreover, each additional tool and library you add to your project increases the maintenance burden and the risk of something breaking in the future due to dependency rot or deprecation.
The question then becomes: is there a way to build modern, interactive frontend applications without needing a build step or a complex toolchain? The answer is yes, and I believe the stack I’ve come up with is one of the best options for this use case. The stack I’ve come up with consists of Preact, HTM, and Twind.
How it works
Preact and HTM are bundled and vendored together. Preact gives us the same reactivity as React, while HTM allows us to use a JSX-like language directly in normal JS files using tagged template literals. This allows us to have a very similar experience to using React with JSX, but without any build step or transpilation. You can write your components in plain JavaScript files, use things like useState and useEffect, and everything will work seamlessly in the browser. There are several vscode extensions that provide syntax highlighting for HTM, so you can get a great editing experience without needing to set up a full React environment. My personal favorite is lit-html.
Twind is also vendored, which gives us the ability to use Tailwind classes on our elements for styling without a build step. It is fully compatible with Tailwind v3, so you get the utility-first workflow without needing a watcher or a compiler running in the background.
Here is an example of what a simple counter component looks like using this stack. You’ll notice that we can use all of the modern React-like features without any build step, and the styling is done with Tailwind classes directly in the template literals.
// Counter.js
import { html, useState } from './vendor/preact.standalone.module.js';
export function Counter() {
const [count, setCount] = useState(0);
return html`
<div class="p-4 border rounded shadow-sm">
<h2 class="text-xl font-bold mb-4">Count: ${count}</h2>
<button
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
onClick=${() => setCount(count + 1)}
>
Increment
</button>
</div>
`;
}
// App.js
import { html, render } from './vendor/preact.standalone.module.js';
import { Counter } from './Counter.js';
function App() {
return html`
<div class="max-w-md mx-auto mt-10">
<h1 class="text-2xl font-bold mb-6">No-Build Frontend Stack</h1>
<${Counter} />
</div>
`;
}
// render the app in the '#root' element of the HTML page
render(html`<${App} />`, document.getElementById('root'));
Fully vendored and portable
One of the biggest advantages here is that everything is fully vendored. There is no reliance on external CDNs or package managers. This means as long as you have a zip of the source code and a basic static file server, your app will work forever. You don’t have to worry about a library disappearing from a CDN or a package breaking years down the line. If you’ve been around long enough, you’re probably familiar with the phenomenon of “dependency rot” where projects break because a critical dependency is no longer available or one of your tools has been deprecated (who else remembers Bower?). By vendoring everything, we completely eliminate that risk. Your app will work in 5, 10, or even 20 years without any changes needed.
Routing
Routing is handled client-side via hash-based routing (for example, #/home, #/about). While non-hash-based routing is definitely still possible, using hashes keeps the deployment process completely frictionless on almost any static host.
A note on HTMX
HTMX can be a fine choice if you’re building full-stack applications that fit into a certain class of apps. You can create surprisingly rich user experiences with HTMX, but there are limitations.
I actually really enjoy HTMX - I even did a workshop on it at Hack the North in 2024: HTMX Workshop. However, I find that I don’t personally reach for it very often. It’s simple, but it requires you to think about your applications differently in a way that I don’t typically think about my projects.
For this article, I’m referring specifically to frontend applications where user interactions on the client side are the main focus. If you’re building something full-stack, you might want HTMX, but for pure frontend work, this Preact-based stack feels much more natural to me.
A note on TypeScript
Let’s address the elephant in the room: TypeScript. Creating a frontend application in today’s ecosystem without TypeScript is like heresy. I don’t think we can understate the importance of TypeScript in modern web development. It provides type safety, better tooling, and can help catch bugs throughout the development process.
That being said - especially in the age of agentic coding assistants - I don’t think TypeScript is strictly necessary for every project. If you’re building a small to medium-sized frontend application, you can get away with plain JavaScript and still have a great developer experience. And truthfully, if you’re building a larger application, this stack is probably not the best choice anyway. For larger applications, you might want to consider a more traditional React setup with TypeScript and a build step.
I’ve also heard of using jsdoc comments to get some of the benefits of TypeScript without needing a build step. This can be a good middle ground if you want some type safety and better tooling without the overhead of a full TypeScript setup. I haven’t personally tried this approach, but it seems like a reasonable option for those who want some of the benefits of TypeScript without the build step.
Try the template
I created a template repository using this stack which you can find here: jere-mie/preact-htm-template.
You can also check out the live preview here. It features multiple pages with interactive elements and is easy to use as a starting point for your own projects.
If you want to start from scratch, I recommend checking out this tool which bundles Preact and HTM together in a single file that you can include in your project. Twind, you can download from their website.