
React
Turn AI- or config-generated JSON UI specs into typed React trees with @json-render/react catalogs and registries.
Overview
react (json-render) is an agent skill for the Build phase that maps JSON UI specs to React components via @json-render/react catalogs and Renderer.
Install
npx skills add https://github.com/vercel-labs/json-render --skill reactWhat is this skill?
- defineRegistry pairs a Zod-validated catalog with React component implementations
- Renderer mounts a JSON spec into a React component tree from registry mappings
- Props schemas per component (Button, Card, etc.) with nullable enums for safe AI output
- Works with @json-render/core defineCatalog and react/schema for shared typing
- Quick-start pattern: catalog export + registry + <Renderer spec={spec} />
Adoption & trust: 2.3k installs on skills.sh; 15k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your agent outputs JSON layouts but you lack a typed, repeatable way to render them as real React components.
Who is it for?
Builders using json-render who want Zod-scoped component catalogs and a single Renderer entry point for AI-generated specs.
Skip if: Teams that need only static hand-coded pages with no JSON-driven or generative UI path.
When should I use this skill?
Working with @json-render/react, building React UIs from JSON, creating component catalogs, or rendering AI-generated specs.
What do I get? / Deliverables
You ship a catalog plus registry so JSON specs render as validated React UI without rewriting JSX for every generated variant.
- Exported catalog with Zod prop schemas per UI component
- Registry and Renderer integration that mounts specs in the app
Recommended Skills
Journey fit
Rendering and catalog wiring happen while you build the product UI layer, not during distribution or ops. defineCatalog, defineRegistry, and Renderer are React frontend concerns for mapping spec nodes to components.
How it compares
React renderer layer for json-render—not a full design system or alternate meta-framework like plain RSC-only apps.
Common Questions / FAQ
Who is react (json-render) for?
Solo developers building SaaS or agent UIs in React who standardize on @json-render for AI-generated or config-driven screens.
When should I use react (json-render)?
Use it during Build frontend work when integrating @json-render/react, defining component catalogs, or rendering specs from your agent pipeline.
Is react (json-render) safe to install?
It is documentation for an npm library; review the Security Audits panel on this Prism page and pin @json-render/react versions in your own lockfile.
SKILL.md
READMESKILL.md - React
# @json-render/react React renderer that converts JSON specs into React component trees. ## Quick Start ```typescript import { defineRegistry, Renderer } from "@json-render/react"; import { catalog } from "./catalog"; const { registry } = defineRegistry(catalog, { components: { Card: ({ props, children }) => <div>{props.title}{children}</div>, }, }); function App({ spec }) { return <Renderer spec={spec} registry={registry} />; } ``` ## Creating a Catalog ```typescript import { defineCatalog } from "@json-render/core"; import { schema } from "@json-render/react/schema"; import { defineRegistry } from "@json-render/react"; import { z } from "zod"; // Create catalog with props schemas export const catalog = defineCatalog(schema, { components: { Button: { props: z.object({ label: z.string(), variant: z.enum(["primary", "secondary"]).nullable(), }), description: "Clickable button", }, Card: { props: z.object({ title: z.string() }), description: "Card container with title", }, }, }); // Define component implementations with type-safe props const { registry } = defineRegistry(catalog, { components: { Button: ({ props }) => ( <button className={props.variant}>{props.label}</button> ), Card: ({ props, children }) => ( <div className="card"> <h2>{props.title}</h2> {children} </div> ), }, }); ``` ## Spec Structure (Element Tree) The React schema uses an element tree format: ```json { "root": { "type": "Card", "props": { "title": "Hello" }, "children": [ { "type": "Button", "props": { "label": "Click me" } } ] } } ``` ## Visibility Conditions Use `visible` on elements to show/hide based on state. New syntax: `{ "$state": "/path" }`, `{ "$state": "/path", "eq": value }`, `{ "$state": "/path", "not": true }`, `{ "$and": [cond1, cond2] }` for AND, `{ "$or": [cond1, cond2] }` for OR. Helpers: `visibility.when("/path")`, `visibility.unless("/path")`, `visibility.eq("/path", val)`, `visibility.and(cond1, cond2)`, `visibility.or(cond1, cond2)`. ## Providers | Provider | Purpose | |----------|---------| | `StateProvider` | Share state across components (JSON Pointer paths). Accepts optional `store` prop for controlled mode. | | `ActionProvider` | Handle actions dispatched via the event system | | `VisibilityProvider` | Enable conditional rendering based on state | | `ValidationProvider` | Form field validation | ### External Store (Controlled Mode) Pass a `StateStore` to `StateProvider` (or `JSONUIProvider` / `createRenderer`) to use external state management (Redux, Zustand, XState, etc.): ```tsx import { createStateStore, type StateStore } from "@json-render/react"; const store = createStateStore({ count: 0 }); <StateProvider store={store}>{children}</StateProvider> // Mutate from anywhere — React re-renders automatically: store.set("/count", 1); ``` When `store` is provided, `initialState` and `onStateChange` are ignored. ## Dynamic Prop Expressions Any prop value can be a data-driven expression resolved by the renderer before components receive props: - **`{ "$state": "/state/key" }`** - reads from state model (one-way read) - **`{ "$bindState": "/path" }`** - two-way binding: reads from state and enables write-back. Use on the natural value prop (value, checked, pressed, etc.) of form components. - **`{ "$bindItem": "field" }`** - two-way binding to a repeat item field. Use inside repeat scopes. - **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** - conditional value - **`{ "$template": "Hello, ${/name}!" }`** - interpolates state values into strings - **`{ "$computed": "fn", "args": { ... } }`** - calls reg