# no build · no deps · no rot · ai-native
Reactive components, two-way binding, routing and a 60+ component UI library — running straight from source in the browser.
The dependency you never installed can't be the one that bites you.
pulled transitively, from maintainers you'll never meet
read once, reviewed once, then simply yours
npm update, because there is no npmThese run in a sandbox from the same source you'd write — code on the left, the living result on the right. Change the code and hit Run.
// a component is a class — reactive state, no setState, no virtual DOM
// two-way binding + lists — x-model, each(), when(), on-* handlers
// shared state, zero ceremony — one store, many components, no prop-drilling or provider
$ (no build)
ES modules run directly in the browser. Save a file, refresh. There is no compiler between you and the page.
deps: 0
Nothing from npm — not even transitively. The whole framework is a small set of files you can read.
router + ui
Hash and HTML5 routing, reactive stores, and a 60+ component cl-* UI library, all in the box.
<my-widget>
Import a component into any HTML page and use its tag. Perfect for a backend that just serves files.
xss ✕
Auto-escaping, URL-scheme allowlisting, and raw HTML gated behind an explicit, trust-marked opt-in.
light DOM
No shadow DOM. Your components are right there in the element tree — inspect, tweak, and debug them like normal HTML.
A modern component model without React's build chain — or vanilla's manual DOM wiring.
| VDX | React | Vanilla JS | htmx | |
|---|---|---|---|---|
| Build step | None | Required | None | None |
| Bundling & linting | Optional | Required | DIY | None |
| TypeScript | Optional | Via build | DIY | — |
| npm dependencies | Zero | Many | Zero | One script |
| Reactive state | Built in | Built in | Roll your own | Server round-trip |
| Manual DOM sync | Never | Never | Constant | Server-driven |
| XSS-safe by default | Yes | Yes | On you | On you |
| Two-way binding | x-model | Manual | Manual | — |
| Router + UI library | Included | Add packages | Add packages | — |
| Supply-chain surface | None | Large | None | Tiny |
| Survives a framework era | Vendored | Churns | Forever | Stable |
# ai-native
Most frameworks assume a human who already knows them — the right hooks, this year's patterns, the current build config. VDX assumes a reader starting from the files in front of them, human or model.
# one file
Point an agent at the source — or the single-file FRAMEWORK.md — and it has the whole model. No plugin matrix, no version-specific lore, no build config to reverse-engineer.
el.state
No shadow DOM, so any component is reachable from the DOM. Read or poke its live state in plain JS ($ is your devtools' querySelector) — no framework extension needed.$('cart-badge').stores.cart.count
no hooks
No hooks, no renderer, no act(). Grab the element, call its methods, read its state. The wiring that made React hooks a testing chore simply isn't here.
Escaping isn't a function you remember to call — it's the default.
Paste hostile input into the demo: the markup renders as plain text and the
javascript: URL goes nowhere. Rendering raw HTML is the part you ask for —
hit Edit to read the markup.
raw() tags its output at runtime, so a JSON string from an API can never masquerade as trusted markup.raw(userInput) in the source, easy to spot in review and to grep for.The questions you'd actually ask before betting on a small framework.
Honestly: it's a side project, not a movement. But it's one the author builds real software with — the largest app on it is an extensive music player whose windowed 10,000-track queues and touch gestures are the reason those are first-class features here — and it's maintained for the most reliable reason there is: so those apps never rot.
Then you have exactly what you had yesterday: a folder of readable source with zero upstream dependencies. The long-term bet is that browsers keep not breaking userspace — a far safer bet than every package in a typical React tree staying healthy. The codebase is also small and legible enough that AI agents do real maintenance on it today; the commit history is the proof.
The framework is a single ~27 KB gzipped file (~33 KB with the router and utils), and the readable core is about 8,000 lines — an afternoon, not an archaeology project. That loads faster than many bundled SPAs; a heavily optimized SSR stack will still beat it to first paint. It's small and honest, and there's no hydration step to pay for.
Anything modern — evergreen desktop and mobile. The polyfill era is over:
build steps today mostly exist for TypeScript and JSX, and here both are
unnecessary — templates are tagged literals, and TypeScript is supported via
shipped .d.ts files and tsc --noEmit.
No SSR, on purpose. Where SEO actually matters — content pages — the islands model keeps your content (or whatever your backend, CMS, or Hugo generates) as real static HTML and drops components into it, so there's nothing to hydrate and no server-side rendering surface to secure. For app screens behind a login, SSR was never buying you much. Service workers and offline support are in the box.
VDX ships as versioned releases (v1 up) with release notes. Updating is:
replace your vdx/ folder, skim the notes, run your tests. No
lockfile solver, no peer-dependency sudoku — the diff is the whole story.
No installer to trust, no toolchain to set up. Drop the files in, serve them, done.
curl -LO https://github.com/iwalton3/vdx-web/releases/latest/download/vdx-full.zip unzip vdx-full.zip -d your-app/ # vendored into your-app/vdx/ # smaller cuts: vdx-core.zip · vdx-framework.zip · vdx-ui.zip — or clone the repo and copy lib/ui/styles
cd your-app && python3 -m http.server 9000 # any static server — nothing to install<!-- in your page --> <my-widget></my-widget> <script type="module"> import { defineComponent, Component, html } from './vdx/lib/framework.js'; </script>