Claude-skill-registry json-render-ui

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

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/json-render-ui" ~/.claude/skills/majiayu000-claude-skill-registry-json-render-ui && rm -rf "$T"
manifest: skills/data/json-render-ui/SKILL.md
source content

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

ComponentPropsChildrenDescription
Card
title?
,
description?
,
padding?: sm|md|lg
YesContainer with optional header
Grid
columns?: 1-4
,
gap?: sm|md|lg
YesCSS grid layout
Stack
direction?: horizontal|vertical
,
gap?: sm|md|lg
,
align?: start|center|end|stretch
YesFlexbox stack

Data Display

ComponentPropsChildrenDescription
Metric
label
,
valuePath
,
format?: number|currency|percent
,
trend?: up|down|neutral
,
trendValue?
NoSingle KPI display
Chart
type: bar|line|pie|area
,
dataPath
,
title?
,
height?
NoData visualization
Table
dataPath
,
columns: [{key, label, format?: text|currency|date|badge}]
NoTabular data
List
dataPath
,
emptyMessage?
YesRendered list from array

Interactive

ComponentPropsChildrenDescription
Button
label
,
action
,
variant?: primary|secondary|danger|ghost
,
size?: sm|md|lg
,
disabled?
NoClickable action
Select
label?
,
bindPath
,
options: [{value, label}]
,
placeholder?
NoDropdown select
DatePicker
label?
,
bindPath
,
placeholder?
NoDate input

Typography

ComponentPropsChildrenDescription
Heading
text
,
level?: h1|h2|h3|h4
NoSection heading
Text
content
,
variant?: body|caption|label
,
color?: default|muted|success|warning|danger
NoText paragraph

Status

ComponentPropsChildrenDescription
Badge
text
,
variant?: default|success|warning|danger|info
NoStatus indicator
Alert
type: info|success|warning|error
,
title
,
message?
,
dismissible?
NoNotification banner

Special

ComponentPropsChildrenDescription
Divider
label?
NoVisual separator
Empty
title
,
description?
,
action?
,
actionLabel?
NoEmpty 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:

  1. Embeds the UITree JSON
  2. Imports the renderer from
    assets/renderer.js
    (inline it)
  3. 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