I recently shipped a desktop app. No React. No npm. No node_modules. AI generated most of the UI code, and it worked better without a framework than it ever would have with one.
Streaming real-time content, managing complex state, drag-and-drop reordering, resizable layouts -- all in plain Web Components and imperative DOM manipulation. Zero runtime dependencies.
This wasn't an ideological choice. It just turned out that when AI writes your UI, frameworks get in the way more than they help.
Why frameworks existed
Think about what React actually solved when it came out. The browser DOM API was painful. Managing state across components was a mess. Keeping the UI in sync with data required tons of boilerplate. Frameworks abstracted all of that away.
But that was 2013. Since then, two things changed:
The platform caught up. Web Components, custom elements, CustomEvent, CSS custom properties, prefers-color-scheme, ResizeObserver, MutationObserver, template literals. The browser now has native answers to most of the problems that React was invented to solve.
AI writes the boilerplate. The remaining argument for frameworks is developer ergonomics -- less repetitive code. But when AI generates your components, that argument disappears. AI doesn't get bored writing document.createElement. It doesn't need JSX to be productive. It just writes the code, and the code uses APIs that every model knows because they've been in every browser for years.
So you end up with: the platform handles the hard stuff natively, and AI handles the tedious stuff. What's left for the framework to do?
The setup
The app is an Electron desktop app. The renderer is the part users interact with: a chat panel, tab bar, agent sidebar, task panel, status line. Standard desktop app stuff.
When I started, I figured I'd add React later when things got complex enough. That moment never came.
What the code actually looks like
Every component in the app follows the same pattern. There's a render() method. When state changes, it gets called. It updates the DOM.
That's it. That's the architecture.
The DOM structure gets built once. After that, updates only touch what actually changed. No virtual DOM doing the diffing for me. I know what changed because I'm the one who changed it.
React's entire selling point is "you describe what the UI should look like and we figure out the minimal DOM updates." But if you already know what changed... you don't need someone to figure it out. You just update that thing.
DOM caching without a virtual DOM
The chat component renders message blocks from an AI agent -- text, code, tool calls, tool results. Messages stream in real-time. This needs to be fast.
My approach: a WeakMap that tracks what each DOM element was last rendered from. On update, compare the cache entry. If it matches, skip it. Remove elements that no longer exist, append new ones.
This is what React's reconciler does, except I'm doing it for the one place that actually needs it. The rest of the app doesn't need diffing at all -- the DOM structure is stable, only content changes.
Event delegation over binding
Instead of attaching click handlers to every interactive element, I attach one handler to the container. It checks what was clicked using closest() and acts accordingly. New elements added to the DOM? Already covered. No need to bind or unbind anything.
This is old-school DOM programming. jQuery developers did this in 2010. It still works great.
What AI gets wrong with frameworks
Here's the thing nobody talks about. Ask AI to build you a component in React and it'll give you something that looks right. But then you need state management -- and it picks a library you don't use. Or it uses an older API pattern. Or it generates a hook that doesn't compose well with the rest of your app. You spend time fixing the framework-specific parts, not the actual logic.
Ask AI to do the same thing with plain DOM manipulation and there's nothing to get wrong. createElement, appendChild, addEventListener -- these APIs haven't changed. There's no version mismatch, no deprecated patterns, no competing conventions for how to structure things.
The framework was supposed to make development faster. But when AI writes the code, the framework becomes the part that slows you down -- it's the thing that needs to be done correctly according to conventions that the model may or may not know.
Why you don't need npm either
I needed a markdown parser for rendering LLM responses. Normally you'd npm install something. Instead I asked AI to generate one. It came out to about 300 lines. Handles code blocks, tables, lists, blockquotes, links, images -- everything that actually shows up in LLM output.
I needed a state store for sharing data between components. AI generated a small one with selector-based subscriptions. About 50 lines.
I needed CSS theming with light/dark mode. That's just CSS custom properties and a prefers-color-scheme media query. The browser does this natively now.
Every time I thought "I need a library for this," I asked AI to write it instead. And every time, the result was a few hundred lines of code that does exactly what I need, nothing more. No transitive dependencies, no breaking changes on update, no 200KB bundle for a feature I use 10% of.
When AI can generate a focused solution in seconds, what's the point of importing a general-purpose library?
The stability argument
Here's a bonus you don't think about until it matters: nothing in my app can break without me changing it.
No dependency will release a version that deprecates an API I use. No framework will ship a migration guide I have to follow. No package in my tree will get a CVE that forces an emergency update on a Friday night.
When your code only depends on browser APIs, the only thing that can break it is the browser. And browsers don't break backwards compatibility. A Web Component I write today will work in 2030. Can you say that about your React 19 code?
When this doesn't apply
I'm not going to pretend this works for everything. If you have a team of 20 people and everyone knows React, use React. The shared conventions are worth more than the technical purity.
But if you're building something yourself, or with AI doing most of the generation -- consider whether the framework is helping you or just giving AI more ways to make mistakes.
The platform handles the hard stuff natively. AI handles the tedious stuff. Frameworks used to sit in between. I'm not sure they need to anymore.
AgentWFY is open source, MIT licensed. The renderer code is in src/renderer/ if you want to see how all of this looks in practice.
Top comments (0)