name: json-render-ui
description: Generate guardrailed UI from natural language. Claude emits constrained JSON, skill runtime renders via Preact. Use when user provides json and requests: Dashboards with metrics, charts, tables; Admin panels; Data visualization interfaces; Form-based applications
metadata:
version: 0.0.1
JSON Render UI
Overview
Transform natural language UI requests into working dashboards and applications. Claude acts as the translation layer (prompt → JSON), the skill provides the rendering runtime (JSON → UI).
Architecture:
User prompt → Claude (constrained by catalog) → UITree JSON → Preact renderer → UI
Output Format
Claude emits a UITree structure:
{
"root": "main",
"elements": {
"main": {
"key": "main",
"type": "Grid",
"props": { "columns": 2, "gap": "md" },
"children": ["metric1", "metric2"]
},
"metric1": {
"key": "metric1",
"type": "Metric",
"props": {
"label": "Revenue",
"valuePath": "/revenue",
"format": "currency"
}
},
"metric2": {
"key": "metric2",
"type": "Metric",
"props": {
"label": "Growth",
"valuePath": "/growth",
"format": "percent"
}
}
},
"data": {
"revenue": 125000,
"growth": 0.15
}
}
Component Catalog
Claude can ONLY use these components. This is the guardrail.
Layout Components
| Component |
Props |
Children |
Description |
Card |
title?, description?, padding?: sm|md|lg |
Yes |
Container with optional header |
Grid |
columns?: 1-4, gap?: sm|md|lg |
Yes |
CSS grid layout |
Stack |
direction?: horizontal|vertical, gap?: sm|md|lg, align?: start|center|end|stretch |
Yes |
Flexbox stack |
Data Display
| Component |
Props |
Children |
Description |
Metric |
label, valuePath, format?: number|currency|percent, trend?: up|down|neutral, trendValue? |
No |
Single KPI display |
Chart |
type: bar|line|pie|area, dataPath, title?, height? |
No |
Data visualization |
Table |
dataPath, columns: [{key, label, format?: text|currency|date|badge}] |
No |
Tabular data |
List |
dataPath, emptyMessage? |
Yes |
Rendered list from array |
Interactive
| Component |
Props |
Children |
Description |
Button |
label, action, variant?: primary|secondary|danger|ghost, size?: sm|md|lg, disabled? |
No |
Clickable action |
Select |
label?, bindPath, options: [{value, label}], placeholder? |
No |
Dropdown select |
DatePicker |
label?, bindPath, placeholder? |
No |
Date input |
Typography
| Component |
Props |
Children |
Description |
Heading |
text, level?: h1|h2|h3|h4 |
No |
Section heading |
Text |
content, variant?: body|caption|label, color?: default|muted|success|warning|danger |
No |
Text paragraph |
Status
| Component |
Props |
Children |
Description |
Badge |
text, variant?: default|success|warning|danger|info |
No |
Status indicator |
Alert |
type: info|success|warning|error, title, message?, dismissible? |
No |
Notification banner |
Special
| Component |
Props |
Children |
Description |
Divider |
label? |
No |
Visual separator |
Empty |
title, description?, action?, actionLabel? |
No |
Empty state |
Data Binding
Props ending in Path (e.g., valuePath, dataPath, bindPath) reference the data model using JSON Pointer syntax:
/revenue → data.revenue
/users/0/name → data.users[0].name
/filters/dateRange → data.filters.dateRange
Visibility Conditions
Any element can have a visible property:
{
"type": "Alert",
"props": { "type": "error", "title": "Error" },
"visible": { "path": "/hasError" }
}
Visibility expressions:
true / false — Static
{ "path": "/some/path" } — Truthy check
{ "and": [...] } — All conditions true
{ "or": [...] } — Any condition true
{ "not": {...} } — Negation
{ "eq": [a, b] } — Equality
Generating Output
Step 1: Emit UITree JSON
Analyze the user's request and emit a UITree structure. Include sample data that matches the schema.
Step 2: Create Artifact
Create an HTML artifact that:
- Embeds the UITree JSON
- Imports the renderer from
assets/renderer.js (inline it)
- Renders the UI
Use the template in assets/template.html.
Constraints
DO:
- Use only catalog components
- Provide realistic sample data
- Use semantic component choices (Metric for KPIs, Table for tabular data)
- Keep trees flat (no deep nesting beyond 3 levels)
DO NOT:
- Invent new component types
- Use arbitrary HTML/CSS
- Omit required props
- Create deeply nested structures
Example
User: "Create a sales dashboard with revenue, orders, and a chart showing monthly trends"
Claude outputs:
{
"root": "dashboard",
"elements": {
"dashboard": {
"key": "dashboard",
"type": "Stack",
"props": { "direction": "vertical", "gap": "lg" },
"children": ["header", "metrics", "chartCard"]
},
"header": {
"key": "header",
"type": "Heading",
"props": { "text": "Sales Dashboard", "level": "h1" }
},
"metrics": {
"key": "metrics",
"type": "Grid",
"props": { "columns": 3, "gap": "md" },
"children": ["revenue", "orders", "avgOrder"]
},
"revenue": {
"key": "revenue",
"type": "Card",
"props": { "padding": "md" },
"children": ["revenueMetric"]
},
"revenueMetric": {
"key": "revenueMetric",
"type": "Metric",
"props": {
"label": "Total Revenue",
"valuePath": "/revenue",
"format": "currency",
"trend": "up",
"trendValue": "12%"
}
},
"orders": {
"key": "orders",
"type": "Card",
"props": { "padding": "md" },
"children": ["ordersMetric"]
},
"ordersMetric": {
"key": "ordersMetric",
"type": "Metric",
"props": {
"label": "Orders",
"valuePath": "/orders",
"format": "number"
}
},
"avgOrder": {
"key": "avgOrder",
"type": "Card",
"props": { "padding": "md" },
"children": ["avgMetric"]
},
"avgMetric": {
"key": "avgMetric",
"type": "Metric",
"props": {
"label": "Avg Order Value",
"valuePath": "/avgOrderValue",
"format": "currency"
}
},
"chartCard": {
"key": "chartCard",
"type": "Card",
"props": { "title": "Monthly Trends", "padding": "md" },
"children": ["chart"]
},
"chart": {
"key": "chart",
"type": "Chart",
"props": {
"type": "line",
"dataPath": "/monthlyData",
"height": 300
}
}
},
"data": {
"revenue": 284500,
"orders": 1247,
"avgOrderValue": 228,
"monthlyData": [
{ "month": "Jan", "value": 18000 },
{ "month": "Feb", "value": 22000 },
{ "month": "Mar", "value": 28000 },
{ "month": "Apr", "value": 24000 },
{ "month": "May", "value": 32000 }
]
}
}
Then wrap in the artifact template from assets/template.html.
Files
assets/template.html — Complete artifact template with embedded renderer
assets/catalog.json — Machine-readable component schemas
references/uitree-format.md — Detailed UITree specification
1---2name: json-render-ui3description: Transform natural language UI requests into working dashboards and applications. Claude acts as the translation layer (prompt → JSON), the skill provides the rendering runtime (JSON → UI).4---5
6---
7name: json-render-ui
8description: Generate guardrailed UI from natural language. Claude emits constrained JSON, skill runtime renders via Preact. Use when user provides json and requests: Dashboards with metrics, charts, tables; Admin panels; Data visualization interfaces; Form-based applications
9metadata:
10 version: 0.0.1
11---
12
13# JSON Render UI
14
15## Overview
16
17Transform natural language UI requests into working dashboards and applications. Claude acts as the translation layer (prompt → JSON), the skill provides the rendering runtime (JSON → UI).
18
19**Architecture:**
20```
21User prompt → Claude (constrained by catalog) → UITree JSON → Preact renderer → UI
22```
23
24## Output Format
25
26Claude emits a **UITree** structure:
27
28```json
29{
30 "root": "main",
31 "elements": {
32 "main": {
33 "key": "main",
34 "type": "Grid",
35 "props": { "columns": 2, "gap": "md" },
36 "children": ["metric1", "metric2"]
37 },
38 "metric1": {
39 "key": "metric1",
40 "type": "Metric",
41 "props": {
42 "label": "Revenue",
43 "valuePath": "/revenue",
44 "format": "currency"
45 }
46 },
47 "metric2": {
48 "key": "metric2",
49 "type": "Metric",
50 "props": {
51 "label": "Growth",
52 "valuePath": "/growth",
53 "format": "percent"
54 }
55 }
56 },
57 "data": {
58 "revenue": 125000,
59 "growth": 0.15
60 }
61}
62```
63
64## Component Catalog
65
66Claude can ONLY use these components. This is the guardrail.
67
68### Layout Components
69
70| Component | Props | Children | Description |
71|-----------|-------|----------|-------------|
72| `Card` | `title?`, `description?`, `padding?: sm\|md\|lg` | Yes | Container with optional header |
73| `Grid` | `columns?: 1-4`, `gap?: sm\|md\|lg` | Yes | CSS grid layout |
74| `Stack` | `direction?: horizontal\|vertical`, `gap?: sm\|md\|lg`, `align?: start\|center\|end\|stretch` | Yes | Flexbox stack |
75
76### Data Display
77
78| Component | Props | Children | Description |
79|-----------|-------|----------|-------------|
80| `Metric` | `label`, `valuePath`, `format?: number\|currency\|percent`, `trend?: up\|down\|neutral`, `trendValue?` | No | Single KPI display |
81| `Chart` | `type: bar\|line\|pie\|area`, `dataPath`, `title?`, `height?` | No | Data visualization |
82| `Table` | `dataPath`, `columns: [{key, label, format?: text\|currency\|date\|badge}]` | No | Tabular data |
83| `List` | `dataPath`, `emptyMessage?` | Yes | Rendered list from array |
84
85### Interactive
86
87| Component | Props | Children | Description |
88|-----------|-------|----------|-------------|
89| `Button` | `label`, `action`, `variant?: primary\|secondary\|danger\|ghost`, `size?: sm\|md\|lg`, `disabled?` | No | Clickable action |
90| `Select` | `label?`, `bindPath`, `options: [{value, label}]`, `placeholder?` | No | Dropdown select |
91| `DatePicker` | `label?`, `bindPath`, `placeholder?` | No | Date input |
92
93### Typography
94
95| Component | Props | Children | Description |
96|-----------|-------|----------|-------------|
97| `Heading` | `text`, `level?: h1\|h2\|h3\|h4` | No | Section heading |
98| `Text` | `content`, `variant?: body\|caption\|label`, `color?: default\|muted\|success\|warning\|danger` | No | Text paragraph |
99
100### Status
101
102| Component | Props | Children | Description |
103|-----------|-------|----------|-------------|
104| `Badge` | `text`, `variant?: default\|success\|warning\|danger\|info` | No | Status indicator |
105| `Alert` | `type: info\|success\|warning\|error`, `title`, `message?`, `dismissible?` | No | Notification banner |
106
107### Special
108
109| Component | Props | Children | Description |
110|-----------|-------|----------|-------------|
111| `Divider` | `label?` | No | Visual separator |
112| `Empty` | `title`, `description?`, `action?`, `actionLabel?` | No | Empty state |
113
114## Data Binding
115
116Props ending in `Path` (e.g., `valuePath`, `dataPath`, `bindPath`) reference the data model using JSON Pointer syntax:
117
118- `/revenue` → `data.revenue`
119- `/users/0/name` → `data.users[0].name`
120- `/filters/dateRange` → `data.filters.dateRange`
121
122## Visibility Conditions
123
124Any element can have a `visible` property:
125
126```json
127{
128 "type": "Alert",
129 "props": { "type": "error", "title": "Error" },
130 "visible": { "path": "/hasError" }
131}
132```
133
134Visibility expressions:
135- `true` / `false` — Static
136- `{ "path": "/some/path" }` — Truthy check
137- `{ "and": [...] }` — All conditions true
138- `{ "or": [...] }` — Any condition true
139- `{ "not": {...} }` — Negation
140- `{ "eq": [a, b] }` — Equality
141
142## Generating Output
143
144### Step 1: Emit UITree JSON
145
146Analyze the user's request and emit a UITree structure. Include sample data that matches the schema.
147
148### Step 2: Create Artifact
149
150Create an HTML artifact that:
1511. Embeds the UITree JSON
1522. Imports the renderer from `assets/renderer.js` (inline it)
1533. Renders the UI
154
155Use the template in `assets/template.html`.
156
157## Constraints
158
159**DO:**
160- Use only catalog components
161- Provide realistic sample data
162- Use semantic component choices (Metric for KPIs, Table for tabular data)
163- Keep trees flat (no deep nesting beyond 3 levels)
164
165**DO NOT:**
166- Invent new component types
167- Use arbitrary HTML/CSS
168- Omit required props
169- Create deeply nested structures
170
171## Example
172
173**User:** "Create a sales dashboard with revenue, orders, and a chart showing monthly trends"
174
175**Claude outputs:**
176
177```json
178{
179 "root": "dashboard",
180 "elements": {
181 "dashboard": {
182 "key": "dashboard",
183 "type": "Stack",
184 "props": { "direction": "vertical", "gap": "lg" },
185 "children": ["header", "metrics", "chartCard"]
186 },
187 "header": {
188 "key": "header",
189 "type": "Heading",
190 "props": { "text": "Sales Dashboard", "level": "h1" }
191 },
192 "metrics": {
193 "key": "metrics",
194 "type": "Grid",
195 "props": { "columns": 3, "gap": "md" },
196 "children": ["revenue", "orders", "avgOrder"]
197 },
198 "revenue": {
199 "key": "revenue",
200 "type": "Card",
201 "props": { "padding": "md" },
202 "children": ["revenueMetric"]
203 },
204 "revenueMetric": {
205 "key": "revenueMetric",
206 "type": "Metric",
207 "props": {
208 "label": "Total Revenue",
209 "valuePath": "/revenue",
210 "format": "currency",
211 "trend": "up",
212 "trendValue": "12%"
213 }
214 },
215 "orders": {
216 "key": "orders",
217 "type": "Card",
218 "props": { "padding": "md" },
219 "children": ["ordersMetric"]
220 },
221 "ordersMetric": {
222 "key": "ordersMetric",
223 "type": "Metric",
224 "props": {
225 "label": "Orders",
226 "valuePath": "/orders",
227 "format": "number"
228 }
229 },
230 "avgOrder": {
231 "key": "avgOrder",
232 "type": "Card",
233 "props": { "padding": "md" },
234 "children": ["avgMetric"]
235 },
236 "avgMetric": {
237 "key": "avgMetric",
238 "type": "Metric",
239 "props": {
240 "label": "Avg Order Value",
241 "valuePath": "/avgOrderValue",
242 "format": "currency"
243 }
244 },
245 "chartCard": {
246 "key": "chartCard",
247 "type": "Card",
248 "props": { "title": "Monthly Trends", "padding": "md" },
249 "children": ["chart"]
250 },
251 "chart": {
252 "key": "chart",
253 "type": "Chart",
254 "props": {
255 "type": "line",
256 "dataPath": "/monthlyData",
257 "height": 300
258 }
259 }
260 },
261 "data": {
262 "revenue": 284500,
263 "orders": 1247,
264 "avgOrderValue": 228,
265 "monthlyData": [
266 { "month": "Jan", "value": 18000 },
267 { "month": "Feb", "value": 22000 },
268 { "month": "Mar", "value": 28000 },
269 { "month": "Apr", "value": 24000 },
270 { "month": "May", "value": 32000 }
271 ]
272 }
273}
274```
275
276Then wrap in the artifact template from `assets/template.html`.
277
278## Files
279
280- `assets/template.html` — Complete artifact template with embedded renderer
281- `assets/catalog.json` — Machine-readable component schemas
282- `references/uitree-format.md` — Detailed UITree specification