vertz/ui is the UI layer of the Vertz stack. You write standard TypeScript and JSX — the compiler transforms it into fine-grained DOM updates at build time. No virtual DOM, no hooks, no manual subscriptions.
How the compiler works
The Vertz compiler runs as a build plugin (Bun or Vite). It analyzes your component code and applies three key transforms:let becomes a signal
let count = 0 compiles to const count = signal(0). Assignments like count++ become count.value++. You never import or call signal() yourself.const becomes computed
const double = count * 2 compiles to const double = computed(() => count.value * 2). The compiler detects the dependency on count automatically.What’s included
vertz/ui is a single package that covers what typically requires multiple libraries:
| Feature | What it replaces |
|---|---|
| Reactive signals | React hooks (useState, useMemo, useEffect) |
| JSX runtime | React DOM |
| Router | React Router / Next.js App Router |
| Data fetching | TanStack Query / SWR |
| Form handling | React Hook Form / Formik |
| Scoped CSS | Tailwind / CSS Modules / styled-components |
| Context | React Context |
| SSR + Hydration | Next.js / Remix |
Architecture
The UI layer is split into three packages:vertz/ui— the runtime: signals, JSX factory, router, query, form, CSS, contextvertz/ui-compiler— the build plugin: transformslet/const, generates reactive props, compiles conditionals and listsvertz/ui-server— SSR renderer, dev server with HMR, hydration support
vertz and import from vertz/ui in your application code. The compiler and server are build-time concerns.
Core principles
Components run once
Unlike React, Vertz components are not re-executed when state changes. The function runs once to create the DOM tree. Signals and effects handle all subsequent updates. This means:- No stale closure bugs
- No dependency arrays
- No
useCallback/useMemowrappers - Predictable execution — your component body runs exactly once
The compiler does the work
You write natural TypeScript. The compiler adds the reactive wiring. This is not magic — the transforms are deterministic and predictable:let→ always a signalconstwith reactive deps → always computed- JSX props with reactive expressions → always getters
Fine-grained updates
Whencount changes, only the text node showing count updates. The parent div, sibling elements, and other text nodes are untouched. No tree diffing, no reconciliation.
Guides
Components
Props, children, conditionals, lists, and component patterns.
Reactivity
Signals, computed values, effects, and watch.
Styling
Scoped CSS with
css() and parameterized styles with variants().Routing
Type-safe routing with
defineRoutes() and createRouter().Data Fetching
Fetch and cache data with
query().Forms
Type-safe forms with schema validation.