Changelog

Notable changes and updates to json-render.

v0.6.0

February 2026

New: Chat Mode (Inline GenUI)

json-render now supports two generation modes: Generate (JSONL-only, the default) and Chat (text + JSONL inline). Chat mode lets the AI respond conversationally with embedded UI specs, ideal for chatbots and copilot experiences.

// Generate mode (default) — AI outputs only JSONL
const prompt = catalog.prompt();

// Chat mode — AI outputs text + JSONL inline
const chatPrompt = catalog.prompt({ mode: "chat" });

On the server, pipeJsonRender() separates text from JSONL patches in a mixed stream:

import { pipeJsonRender } from "@json-render/core";
import { createUIMessageStream, createUIMessageStreamResponse } from "ai";

const stream = createUIMessageStream({
  execute: async ({ writer }) => {
    writer.merge(pipeJsonRender(result.toUIMessageStream()));
  },
});
return createUIMessageStreamResponse({ stream });

On the client, useJsonRenderMessage extracts the spec and text from message parts:

import { useJsonRenderMessage } from "@json-render/react";

function ChatMessage({ message }) {
  const { spec, text, hasSpec } = useJsonRenderMessage(message.parts);
  return (
    <div>
      {text && <Markdown>{text}</Markdown>}
      {hasSpec && <Renderer spec={spec} registry={registry} />}
    </div>
  );
}

New: AI SDK Integration

First-class Vercel AI SDK support with typed data parts and stream utilities.

  • SpecDataPart type for data-spec stream parts (patch, flat, nested payloads)
  • SPEC_DATA_PART / SPEC_DATA_PART_TYPE constants for type-safe part filtering
  • createJsonRenderTransform() low-level TransformStream for custom pipelines
  • createMixedStreamParser() for parsing mixed text + JSONL streams

New: Two-Way Binding

Props can now use $bindState and $bindItem expressions for two-way data binding. The renderer resolves bindings and passes a bindings map to components, enabling write-back to state without custom valuePath props.

{
  "type": "Input",
  "props": { "label": "Email", "value": { "$bindState": "/form/email" } }
}
import { useBoundProp } from "@json-render/react";

Input: ({ props, bindings }) => {
  const [value, setValue] = useBoundProp<string>(props.value, bindings?.value);
  return <input value={value ?? ""} onChange={(e) => setValue(e.target.value)} />;
}

New: Expression-Based Props and Visibility

All dynamic expressions now use structured $state, $item, and $index objects instead of string token rewriting. This is simpler, more explicit, and works for both props and visibility conditions.

Props:

{ "title": { "$state": "/user/name" } }
{ "label": { "$item": "title" } }
{ "position": { "$index": true } }

Visibility:

{ "$state": "/isAdmin" }
{ "$state": "/role", "eq": "admin" }
[{ "$state": "/isAdmin" }, { "$state": "/feature" }]
{ "$or": [{ "$state": "/roleA" }, { "$state": "/roleB" }] }
{ "$item": "isActive" }
{ "$index": true, "gt": 0 }

Comparison operators: eq, neq, gt, gte, lt, lte, not.

New: React Chat Hooks

  • useChatUI() — full chat hook with message history, streaming, and spec extraction
  • useJsonRenderMessage() — extract spec + text from a message's parts array
  • buildSpecFromParts() / getTextFromParts() — utilities for working with AI SDK message parts
  • useBoundProp() — two-way binding hook for $bindState / $bindItem

New: Chat Example

Full-featured chat example (examples/chat) with AI agent, tool calls (crypto, GitHub, Hacker News, weather, search), theme toggle, and streaming inline UI generation.

Improved: Renderer Performance

  • ElementRenderer is now React.memo'd for better performance with repeat lists
  • emit is always defined (never undefined)
  • Repeat scope passes the actual item object, eliminating string token rewriting

Improved: Utilities

  • applySpecPatch() — typed wrapper for applying a single patch to a Spec
  • nestedToFlat() — convert nested tree specs to flat format
  • resolveBindings() / resolveActionParam() — resolve binding paths and action params

Breaking Changes

  • { $path } and { path } replaced by { $state }, { $item }, { $index } in props
  • Visibility: { path } -> { $state }, { and/or/not } -> { $and/$or } with not as operator flag
  • DynamicValue: { path: string } -> { $state: string }
  • repeat.path -> repeat.statePath
  • Action params: path -> statePath in setState action
  • actionHandlers -> handlers on JSONUIProvider / ActionProvider
  • AuthState and { auth } visibility conditions removed (model auth as regular state)
  • Legacy catalog API removed: createCatalog, generateCatalogPrompt, generateSystemPrompt
  • React exports removed: createRendererFromCatalog, rewriteRepeatTokens
  • Codegen: traverseTree -> traverseSpec

See the Migration Guide for detailed upgrade instructions.


v0.5.0

February 2026

New: @json-render/react-native

Full React Native renderer with 25+ standard components, data binding, visibility, actions, and dynamic props. Build AI-generated native mobile UIs with the same catalog-driven approach as web.

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react-native/schema";
import {
  standardComponentDefinitions,
  standardActionDefinitions,
} from "@json-render/react-native/catalog";
import { defineRegistry, Renderer } from "@json-render/react-native";

const catalog = defineCatalog(schema, {
  components: { ...standardComponentDefinitions },
  actions: standardActionDefinitions,
});

const { registry } = defineRegistry(catalog, { components: {} });

<Renderer spec={spec} registry={registry} />

Includes standard components for layout (Container, Row, Column, ScrollContainer, SafeArea, Pressable, Spacer, Divider), content (Heading, Paragraph, Label, Image, Avatar, Badge, Chip), input (Button, TextInput, Switch, Checkbox, Slider, SearchBar), feedback (Spinner, ProgressBar), and composite (Card, ListItem, Modal).

New: Event System

Components now use emit to fire named events instead of directly dispatching actions. The element's on field maps events to action bindings, decoupling component logic from action handling.

// Component emits a named event
Button: ({ props, emit }) => (
  <button onClick={() => emit("press")}>{props.label}</button>
),

// Element spec maps events to actions
{
  "type": "Button",
  "props": { "label": "Submit" },
  "on": { "press": { "action": "submit", "params": { "formId": "main" } } }
}

New: Repeat/List Rendering

Elements can now iterate over state arrays using the repeat field. Child elements use { "$item": "field" } to read from the current item and { "$index": true } for the current array index.

{
  "type": "Column",
  "repeat": { "statePath": "/posts", "key": "id" },
  "children": ["post-card"]
}
{
  "type": "Card",
  "props": { "title": { "$item": "title" } }
}

New: User Prompt Builder

Build structured user prompts with optional spec refinement and state context:

import { buildUserPrompt } from "@json-render/core";

// Fresh generation
buildUserPrompt({ prompt: "create a todo app" });

// Refinement (patch-only mode)
buildUserPrompt({ prompt: "add a toggle", currentSpec: spec });

// With runtime state
buildUserPrompt({ prompt: "show data", state: { todos: [] } });

New: Spec Validation

Validate spec structure and auto-fix common issues:

import { validateSpec, autoFixSpec } from "@json-render/core";

const { valid, issues } = validateSpec(spec);
const fixed = autoFixSpec(spec);

Improved: State Management

DataProvider has been renamed to StateProvider with a clearer API. State is now a first-class part of specs. Elements can bind to state via $state expressions, and the built-in setState action updates state directly.

Improved: AI Prompts

Schema prompts now include streaming best practices, repeat/list examples, and state patching guidance. Schemas can also define defaultRules that are always included in generated prompts.

Improved: Documentation

  • All documentation pages migrated to MDX
  • AI-powered documentation chat
  • Dynamic Open Graph images for all docs pages
  • Improved playground

Breaking Changes

  • DataProvider renamed to StateProvider
  • useData renamed to useStateStore, useDataValue to useStateValue, useDataBinding to useStateBinding
  • onAction renamed to emit in component context
  • DataModel type renamed to StateModel
  • Action type renamed to ActionBinding (old name still available but deprecated)

v0.4.0

February 2026

New: Custom Schema System

Create custom output formats with defineSchema. Each renderer now defines its own schema, enabling completely different spec formats for different use cases.

import { defineSchema } from "@json-render/core";

const mySchema = defineSchema((s) => ({
  spec: s.object({
    pages: s.array(s.object({
      title: s.string(),
      blocks: s.array(s.ref("catalog.blocks")),
    })),
  }),
  catalog: s.object({
    blocks: s.map({ props: s.zod(), description: s.string() }),
  }),
}), {
  promptTemplate: myPromptTemplate,
});

New: Component Slots

Components can now define which slots they accept. Use ["default"] for regular children, or named slots like ["header", "footer"] for more complex layouts.

const catalog = defineCatalog(schema, {
  components: {
    Card: {
      props: z.object({ title: z.string() }),
      slots: ["default"],  // accepts children
      description: "A card container",
    },
    Layout: {
      props: z.object({}),
      slots: ["header", "content", "footer"],  // named slots
      description: "Page layout with header, content, footer",
    },
  },
});

New: AI Prompt Generation

Catalogs now generate AI system prompts automatically with catalog.prompt(). The prompt includes all component definitions, props schemas, and action descriptions - ensuring the AI only generates valid specs.

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

const catalog = defineCatalog(schema, {
  components: { /* ... */ },
  actions: { /* ... */ },
});

// Generate system prompt for AI
const systemPrompt = catalog.prompt();

// Use with any AI SDK
const result = await streamText({
  model: "claude-haiku-4.5",
  system: systemPrompt,
  prompt: userMessage,
});

New: @json-render/remotion

Generate AI-powered videos with Remotion. Define video catalogs, stream timeline specs, and render with the Remotion Player.

import { Player } from "@remotion/player";
import { Renderer, schema, standardComponentDefinitions } from "@json-render/remotion";

const catalog = defineCatalog(schema, {
  components: standardComponentDefinitions,
  transitions: standardTransitionDefinitions,
});

<Player
  component={Renderer}
  inputProps={{ spec }}
  durationInFrames={spec.composition.durationInFrames}
  fps={spec.composition.fps}
  compositionWidth={spec.composition.width}
  compositionHeight={spec.composition.height}
/>

Includes 10 standard video components (TitleCard, TypingText, SplitScreen, etc.), 7 transition types, and the ClipWrapper utility for custom components.

New: SpecStream

SpecStream is json-render's streaming format for progressively building specs from JSONL patches. The new compiler API makes it easy to process streaming AI responses.

import { createSpecStreamCompiler } from "@json-render/core";

const compiler = createSpecStreamCompiler<MySpec>();

// Process streaming chunks
const { result, newPatches } = compiler.push(chunk);
setSpec(result); // Update UI with partial result

Improved: Dashboard Example

The dashboard example is now a full-featured accounting dashboard with:

  • Persistent SQLite database with Drizzle ORM
  • RESTful API for customers, invoices, expenses, accounts
  • Draggable widget reordering
  • AI-powered widget generation with streaming
  • Real data binding to database records

Improved: Documentation

  • Interactive playground for testing specs
  • New guides: Custom Schema, Streaming, Code Export
  • Full API reference for all packages
  • Integration guides: A2UI, AG-UI, Adaptive Cards, OpenAPI

Breaking Changes

  • UITree type renamed to Spec
  • Schema is now imported from renderer packages (@json-render/react) not core
  • defineCatalog now requires a schema as first argument

v0.3.0

January 2026

Internal release with codegen foundations.

  • Added @json-render/codegen package (spec traversal and JSX serialization)
  • Configurable AI model via environment variables
  • Documentation improvements and bug fixes

Note: Only @json-render/core was published to npm for this release.


v0.2.0

January 2026

Initial public release.

  • Core catalog and spec types
  • React renderer with contexts for data, actions, visibility
  • AI prompt generation from catalogs
  • Basic streaming support
  • Dashboard example application