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— 98 patches for native HTML (≈ MUI)
Data & logic — @domphy/query, @domphy/table, @domphy/virtual, and @domphy/form expose a framework-agnostic API plus a Domphy adapter at the /domphy subpath. @domphy/router is the exception: createRouter/createRoute ship from the main entry (no /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)
Presentation, 3D & i18n:
@domphy/blocks— 173 composed blocks — sidebars, auth pages, dashboards, effects@domphy/chart— SVG + WebGL charts — line, bar, pie, scatter, gauge…@domphy/three— declarative three.js scene graph on Domphy reactivity@domphy/editor— rich-text editor — Tiptap-compatible API, self-contained engine@domphy/floating— anchor positioning — floating-ui core, zero-dep, powers overlays@domphy/i18n— i18next wrapper with reactivet(listener, key)
App layer & tools:
@domphy/dnd— drag & drop / sortable lists@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/press— static doc site framework; its built-in Markdown pipeline (parseMarkdown/createMarkdown) turns Markdown into Domphy element trees for SSR/SSG (this docs site runs on it)@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 libraries with no first-party package (carousel, maps, date pickers…), 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",
// Without it a <button> defaults to type="submit" and posts any enclosing form.
type: "button",
onClick: () => count.set(count.get() + 1),
// Deliberate solid fill: a fixed shifted background is exactly what
// "tone-background-inherit" flags — suppress it like button({variant:"solid"}) does.
_doctorDisable: "tone-background-inherit",
// 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": {
// Hover steps the solid fill DEEPER (+1), the way button({variant:"solid"})
// does. Lightening it to shift-7 pulled the fill toward the shift-0 label
// and collapsed the gap to 7 steps.
backgroundColor: (listener) =>
themeColor(listener, "shift-10", "primary"),
},
},
};
const App: DomphyElement<"div"> = {
div: [text, button],
};
export default App;