Files
crepes-demo/HOW_IT_WORKS.md
OpenClaw 9b750238c2
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Initial commit: json-render crepes demo
2026-02-09 07:30:54 +01:00

5.2 KiB

🎯 How json-render Works in This Demo

The Flow

User Prompt (in production)
    ↓
AI generates JSON spec (constrained to catalog)
    ↓
json-render Renderer component
    ↓
Beautiful React UI

Step-by-Step Example

1. Define Your Component Catalog

lib/catalog.ts:

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react";
import { z } from "zod";

export const catalog = defineCatalog(schema, {
  components: {
    RecipeHeader: {
      props: z.object({
        title: z.string(),
        chef: z.string(),
        prepTime: z.string(),
      }),
      description: "Header with recipe info",
    },
    IngredientList: {
      props: z.object({
        title: z.string(),
        ingredients: z.array(
          z.object({
            name: z.string(),
            quantity: z.string(),
          })
        ),
      }),
      description: "List of ingredients",
    },
    // ... more components
  },
  actions: {},
});

This is your guardrail: AI can only use these components.

2. Map Components to React

lib/registry.tsx:

import { defineRegistry } from "@json-render/react";
import { catalog } from "./catalog";

export const { registry } = defineRegistry(catalog, {
  components: {
    RecipeHeader: ({ props }) => (
      <div className="bg-amber-50 p-8 rounded-2xl">
        <h1 className="text-4xl font-bold">{props.title}</h1>
        <span>👨‍🍳 Chef: {props.chef}</span>
        <span>⏱️ Prep: {props.prepTime}</span>
      </div>
    ),
    IngredientList: ({ props }) => (
      <div className="bg-green-50 p-6">
        <h3>{props.title}</h3>
        <ul>
          {props.ingredients.map((ing, i) => (
            <li key={i}>
              {ing.quantity} {ing.name}
            </li>
          ))}
        </ul>
      </div>
    ),
    // ... more implementations
  },
});

3. Create a JSON Spec

lib/recipes.ts:

const recipe = {
  root: "root",  // Start rendering from this element
  elements: {
    root: {
      type: "RecipeCard",  // Component from catalog
      props: {
        title: "Crêpes Suzette",
        description: "Classic French dessert"
      },
      children: ["header", "ingredients"]  // Refs to other elements
    },
    header: {
      type: "RecipeHeader",
      props: {
        title: "Crêpes Suzette",
        chef: "Auguste Escoffier",
        prepTime: "45 minutes"
      }
    },
    ingredients: {
      type: "IngredientList",
      props: {
        title: "Ingredients",
        ingredients: [
          { quantity: "200g", name: "Flour" },
          { quantity: "4", name: "Eggs" },
          { quantity: "500ml", name: "Milk" }
        ]
      }
    }
  }
};

This is what AI generates (but here we've pre-written it for the demo).

4. Render with json-render

app/page.tsx:

import { Renderer } from "@json-render/react";
import { registry, Provider } from "@/lib/registry";
import { recipes } from "@/lib/recipes";

export default function Home() {
  return (
    <main>
      {recipes.map((recipe, index) => (
        <Provider key={index}>
          <Renderer spec={recipe} registry={registry} />
        </Provider>
      ))}
    </main>
  );
}

Magic happens here: The Renderer takes your spec + registry and outputs fully-styled React components!

What Gets Rendered

The spec above becomes:

<div className="bg-white p-8 rounded-2xl shadow-xl">
  <h2>Crêpes Suzette</h2>
  <p>Classic French dessert</p>
  
  <div className="bg-amber-50 p-8 rounded-2xl">
    <h1 className="text-4xl font-bold">Crêpes Suzette</h1>
    <span>👨‍🍳 Chef: Auguste Escoffier</span>
    <span>⏱️ Prep: 45 minutes</span>
  </div>
  
  <div className="bg-green-50 p-6">
    <h3>Ingredients</h3>
    <ul>
      <li>200g Flour</li>
      <li>4 Eggs</li>
      <li>500ml Milk</li>
    </ul>
  </div>
</div>

Why This Matters

Without json-render:

  • AI generates raw HTML/JSX → Security risk (XSS, code injection)
  • No type safety → Runtime errors
  • Unpredictable output → Broken UIs

With json-render:

  • AI can only use predefined components (guardrailed)
  • Zod schemas enforce type safety (predictable)
  • Your React components control the rendering (safe)
  • Stream rendering as AI generates (fast)

In Production with AI

// User types prompt
const userPrompt = "Show me a recipe for chocolate chip cookies";

// AI generates spec (using your catalog as context)
const aiGeneratedSpec = await ai.generate({
  prompt: userPrompt,
  catalog: catalog.prompt(), // Gives AI the component vocabulary
});

// Render safely
<Renderer spec={aiGeneratedSpec} registry={registry} />

Result: AI-generated UIs that are:

  1. Safe - Can't inject malicious code
  2. Type-safe - Matches your schemas
  3. Beautiful - Uses your styled components
  4. Fast - Streams as AI generates

The Power

You define the components once. Then:

  • AI can generate infinite variations
  • Users can describe UIs in natural language
  • Your app stays safe and consistent
  • No manual UI coding needed

That's json-render.


Check the full code in lib/ to see it in action! 🚀