Define UIs as JSON. Render them anywhere with Web Components.
Warning - This project is for internal/experimental use only. Not production-ready. Use at your own risk.
jsontoui is a complete system for building and rendering user interfaces from JSON definitions - a visual drag-and-drop editor to design layouts, and a standalone renderer library to deploy them.
Drag-and-drop 16 builtin components onto a 12-column grid. Edit properties, configure actions, preview the result.
Live preview inside the editor - toggle to see the rendered result without leaving.
The same JSON rendered as a production-ready UI - no editor, no framework, just Web Components on a CSS grid.
Editor (design tool) --> layout.json --> Renderer (production)
- Design in the visual editor - drag components, set properties, configure actions
- Export a
.jsonfile describing the layout - Render that JSON anywhere - in a standalone page, or embedded in your app via the renderer library
npm install
npm run dev # Editor at http://localhost:5173import { registerBuiltins, mount } from "jsontoui/renderer";
await registerBuiltins();
const layout = {
version: 1,
meta: { name: "hello" },
grid: { columns: 12, rowHeight: 40, gap: 8 },
components: [
{
id: "title",
tag: "jtu-heading",
src: "builtin",
layout: { col: 0, row: 0, colSpan: 12, rowSpan: 1 },
props: { text: "Hello World", level: 2 }
},
{
id: "btn",
tag: "jtu-button",
src: "builtin",
layout: { col: 0, row: 1, colSpan: 4, rowSpan: 1 },
props: { label: "Submit", variant: "default" },
actions: {
click: { type: "webhook", target: "/api/submit", method: "POST" }
}
}
]
};
const cleanup = await mount(layout, "#app");render.html?src=https://api.example.com/layout.json
No build step - just point to a JSON endpoint and it renders.
import { renderFromSchema, collectFormData } from "jsontoui/renderer";
const schema = {
type: "object",
properties: {
name: { type: "string", description: "Full name" },
age: { type: "number", minimum: 0 },
role: { type: "string", enum: ["admin", "user", "guest"] },
active: { type: "boolean", default: true }
},
required: ["name", "role"]
};
const { cleanup } = await renderFromSchema(schema, document.getElementById("form"));
const data = collectFormData(document.getElementById("form"));
// { name: "John", age: 25, role: "admin", active: true }- Drag-and-drop 16 components onto a 12-column grid
- Type-aware property editing (text, number, boolean, enum, JSON)
- Import / export LayoutJSON files
- Preview mode
- Actions config on buttons (webhook POST, URL navigation)
- Component palette with category grouping
mount(json, target)- one-liner to render any layoutrenderFromSchema(schema, target)- auto-generate forms from JSON Schema Draft-07collectFormData(container)- extract form values as a plain object- Actions system - wire clicks to webhook POSTs or redirects
render.html?src=URL- standalone render page- Zero framework dependencies
- External components loaded at runtime via dynamic
import() - Plugins are Web Components that define their own ParamSchema for editor integration
16 Web Components, all using src: "builtin":
| Category | Components |
|---|---|
| Display | jtu-heading jtu-text jtu-badge jtu-card jtu-avatar jtu-separator |
| Form | jtu-input jtu-textarea jtu-select jtu-checkbox jtu-switch jtu-radio jtu-label |
| Action | jtu-button jtu-toggle jtu-dropdown |
interface LayoutJSON {
version: 1;
meta: { name: string; description?: string; author?: string };
grid: { columns: 12; rowHeight: number; gap: number; maxWidth?: number };
components: ComponentJSON[];
theme?: Record<string, string>;
}
interface ComponentJSON {
id: string;
tag: string; // "jtu-input", "jtu-button", etc.
src: string; // "builtin" or URL to external Web Component
layout: { col: number; row: number; colSpan: number; rowSpan: number };
props: Record<string, unknown>;
style?: Record<string, string>;
actions?: Record<string, ActionConfig>;
}
interface ActionConfig {
type: "webhook" | "navigate";
target: string; // URL (http/https only)
method?: string; // "POST" | "GET" (webhook only)
headers?: Record<string, string>;
}npm run dev # Start editor dev server
npm run build # Build editor + renderer
npm run build:renderer # Build renderer only
npm run preview # Preview production build
npm test # Run tests
npm run typecheck # TypeScript type checking| Output | Description |
|---|---|
dist/editor/ |
Deployable SPA (the visual editor) |
dist/renderer/jsontoui-renderer.js |
Importable library (ES + UMD) |
| Function | Async | Description |
|---|---|---|
registerBuiltins() |
yes | Register all 16 builtin Web Components |
parseLayout(input) |
no | Parse and validate JSON into LayoutJSON |
render(layout, target) |
yes | Render a layout to a DOM element. Returns cleanup function |
mount(input, target) |
yes | Parse + render in one call |
renderFromSchema(schema, target) |
yes | Generate form from JSON Schema. Returns { cleanup, unmappedFields } |
collectFormData(container) |
no | Read form values as Record<string, unknown> |
MIT


