# Zoijs design principles **Required reading before proposing a feature.** Zoijs is small on purpose. The things it *doesn't* have are not missing — they were left out deliberately, because each one is a trade we chose not to make. This document explains those choices so the framework stays small, understandable, and predictable for years. For the precise per-capability boundaries (what each package does and doesn't do), see [`docs/scope.md`](docs/scope.md). This page is the *why*; that page is the *what*. --- ## The one idea You write real HTML in a tagged template, keep state in plain reactive values, and `mount` a component. When state changes, Zoijs updates the **exact** text node or attribute that depends on it — nothing else runs. That's the whole framework. Every choice below protects that idea. --- ## Why we left things out ### Why no Virtual DOM? A Virtual DOM re-runs your component, builds a tree, diffs it against the previous tree, and patches the difference. Zoijs binds each dynamic slot **once** and updates the one node that changed. Cost scales with *what changed*, not with app size. No reconciler, no re-render, and none of the stale-closure / dependency-array bugs that come with re-running components. The real DOM is already a tree you can mutate directly — a second virtual copy is overhead we don't need. ### Why no JSX? JSX isn't JavaScript; it needs a compiler, and a compiler means a build step. Zoijs uses tagged template literals (`` html`...` ``) — standard JavaScript that runs in the browser as-is. You write real HTML, parsed once. Nothing to transform, nothing to configure. ### Why no build step? A `