Skip to content
Domphy

Domphy

The AI-friendly UI framework. Patch-based, native elements, no components.

Framework-agnostic, no JSX, no virtual DOM, no build step required — and the most AI-friendly UI framework (learnable from one spec file, self-correcting via @domphy/doctor).

Runtime + design system — tiny, tree-shakeable:

  • @domphy/core — runtime: rendering, reactivity, lifecycle, SSR, CSS-in-JS (≈ react-dom + SSR + CSS-in-JS in one)
  • @domphy/theme — context-aware color/size/spacing tokens
  • @domphy/ui — 96 patches for native HTML (≈ MUI)

Data & logic — framework-agnostic API + a Domphy adapter at the /domphy subpath:

  • @domphy/query — async state (fetching, caching, mutations, infinite queries)
  • @domphy/table — headless tables (sorting, filtering, pagination, grouping)
  • @domphy/router — type-safe routing (nested routes, loaders, search params, SSR)
  • @domphy/virtual — virtualization (rows, columns, dynamic sizes)
  • @domphy/form — forms (typed values, validators, arrays, Standard Schema)

App layer & tools:

  • @domphy/dnd — drag & drop / sortable lists
  • @domphy/palette — color-science toolkit (measure & validate palette quality, 5 CIELAB metrics); design-time companion to theme
  • @domphy/app — Next.js App Router-style framework (routes, layouts, loaders+SWR, metadata, middleware, parallel/intercepting routes, lazy code-split routes, SSR + streaming, API routes)
  • @domphy/markdown — Markdown → Domphy element trees for SSR/SSG (this docs site runs on it)
  • @domphy/mermaid — render Mermaid diagrams (build-time SVG + client patch)
  • @domphy/doctor — static analyzer that flags non-idiomatic code (diagnose/validate; powers AI self-correction)
  • @domphy/mcp — MCP server exposing patches/packages/rules + doctor + app-block registry to agents

Domphy removes component boundaries, unifies SSR and CSR under one model, automates context-aware styling, and works with any JavaScript library without adapters or plugins. For anything outside these packages (charts, rich text, i18n…), use the vanilla library directly — see Integrations.

Why Domphy

From the author:

I published Domphy in February 2026, at 41 years old. I spent 10 years as a structural architect and 6 years teaching myself to code (2 years with js/ts). Every time I tried to learn React or Vue, something felt wrong: logic scattered between data and UI, too many abstractions, too many plugins just to ship a feature. So I built what I wished existed.

I introduce Patch-based UI Architecture, a paradigm for composing web interfaces distinct from component-based, directive-based, and mixin-based approaches. A Patch is formally defined as a function returning a PartialElement: a composable, stateless descriptor that augments a host element's behavior without wrapping, replacing, or owning it. Unlike existing composition models, a Patch carries no rendering lifecycle, holds no state, and creates no DOM boundary.

Installation

npm install @domphy/ui
<script src="https://unpkg.com/@domphy/ui/dist/core-theme-ui.global.js"></script>

Quick Start

import { type DomphyElement, toState } from "@domphy/core";
import { themeColor, themeSpacing } from "@domphy/theme";

// Create a State instance
const count = toState(0);

const text: DomphyElement<"p"> = {
  // Reactive values can be reactive functions.
  // Reading state with `count.get(listener)` also add listener to state.
  // State change => call listener => re render property
  p: (listener) => `Count: ${count.get(listener)}`,
};

const button: DomphyElement<"button"> = {
  button: "Increment",
  onClick: () => count.set(count.get() + 1),

  // Standard Nested CSS nesting
  style: {
    padding: `${themeSpacing(1)} ${themeSpacing(4)}`,
    backgroundColor: (listener) => themeColor(listener, "shift-9", "primary"),
    borderRadius: themeSpacing(1.5),
    color: (listener) => themeColor(listener, "inherit", "primary"),
    "&:hover": {
      backgroundColor: (listener) => themeColor(listener, "shift-7", "primary"),
    },
  },
};

const App: DomphyElement<"div"> = {
  div: [text, button],
};

export default App;