Skip to content
Skill Authoring
Skill

/json-render-ui

Generate guardrailed UI from natural language. Emits constrained JSON that a Preact runtime renders. Use when the request is for a dashboard with metrics, charts, or tables; an admin panel; a data visualization interface; or a form-based application.

BOOST
From plugin
claude-skills
15498 skills1 agent
Install
$ npx -y skills add oaustegard/claude-skills --skill json-render-ui --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/json-render-ui

Context preview

The summary Claude sees to decide when to auto-load this skill.

Generate guardrailed UI from natural language. Emits constrained JSON that a Preact runtime renders. Use when the request is for a dashboard with metrics, charts, or tables; an admin panel; a data visualization interface; or a form-based application.

SKILL.md

json-render-ui.SKILL.md
name: json-render-ui
description: "Generate guardrailed UI from natural language. Emits constrained JSON that a Preact runtime renders. Use when the request is for a dashboard with metrics, charts, or tables; an admin panel; a data visualization interface; or a form-based application."
metadata:
  version: 0.0.2

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: 1. Embeds the UITree JSON 2. Renders the UI

Start from `assets/template.html`, which already carries the embedded renderer — there is no separate `renderer.js` to inline.

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",
Read more
Ships withclaude-skills

A collection of Claude skills distributed as a Claude Code plugin marketplace. Skills are primarily designed for the Claude.ai PaaS skill compute environment; mileage will vary if used as Claude Code Agent Skills.

Get the whole plugin

Other skills on claude-skills.