The End of Hallucinated Interfaces: Inside vercel-labs/json-render
Why generating raw React code is a dead end for AI agents, and how a strict JSON grammar is finally making Generative UI safe for production.
RUG constrains the model to only the UI components you explicitly give it. Components you’ve built, tested, and QA’d. The AI decides which to use. You get dynamic, AI-driven layout without giving up ownership of what actually renders.
- Restrictive UI Generation prevents hallucinations by forcing models to compose pre-approved components instead of writing raw code.
- The framework uses Zod schemas to define a strict vocabulary that validates AI output before it reaches the browser.
- A flat JSON specification allows the same AI-generated intent to render natively across web, mobile, and print platforms.
- Separating abstract logic from implementation details enables developers to integrate dynamic AI features into production apps without sacrificing security.
The Problem with String-Based UI
The first wave of AI-generated user interfaces relied on a simple but flawed premise. Developers asked large language models to write raw HTML, Tailwind classes, or React components as plain text strings. While this works for rapid prototyping, it becomes a liability in production environments.
Unconstrained generation is inherently brittle. When a model is free to write any code it wants, it will inevitably hallucinate invalid syntax, invent non-existent props, or break brand guidelines. Worse, piping raw, AI-generated strings directly into a browser DOM introduces severe security risks and layout instability.
Restrictive UI Generation
The solution to AI hallucinations is not to build a smarter model. The solution is to remove the model's ability to write code entirely. This paradigm is known as Restrictive UI Generation (RUG), and it is the foundation of the json-render framework.
Instead of acting as a programmer typing out React components, the AI acts as a composer filling out a strict, pre-approved form. The framework forces the model to communicate using a predefined JSON grammar. If the AI attempts to use a component that does not exist, or passes a string to a property that requires a number, the validation layer safely catches the error before it ever reaches the user.
Catalog, Registry, and Spec
To enforce these boundaries, json-render splits the UI rendering process into three distinct pillars. This separation of concerns ensures that the AI only handles abstract logic while the host application retains complete control over the actual pixels.
The Catalog acts as the vocabulary. It is a collection of Zod schemas that define exactly which components are available and what properties they accept. These schemas are fed directly into the LLM's system prompt.
The Spec is the instance. It is the flat JSON object streamed back by the AI, containing a root element and an element map. Because it is flat rather than deeply nested, it is highly resilient to the partial updates common in LLM streaming.
Finally, the Registry serves as the concrete implementation. It maps the abstract names defined in the Catalog (such as a generic "Button") to the actual framework-specific code (like a styled React component). The AI never sees or touches the implementation details.
The state the model generates (communicated as JSON) is the sole input to the renderer, which maps that state to your components and data.
Write Once, Render Anywhere
By abstracting the UI into a pure JSON spec, the framework unlocks a powerful cross-platform capability. Because the AI is not generating framework-specific code, the exact same AI output can be piped into entirely different environments.
A single generated payload can be rendered as a React web application, a Vue dashboard, or a React Native mobile screen. The framework even supports specialized renderers, allowing developers to turn the same JSON spec into a static PDF document or a dynamic Remotion video. The AI simply describes the intent, and the platform-specific Registry handles the execution.
Code Generation vs. Schema Mapping
The distinction between traditional AI UI tools and the json-render approach comes down to control. Tools that generate raw code are optimized for developers building new applications from scratch. Schema mapping frameworks are designed for embedding dynamic, AI-driven features into existing, mature codebases.
| Feature | Unconstrained Generation (e.g. OpenUI) | Schema Mapping (json-render) |
|---|---|---|
| Output Format | Raw React, HTML, or Tailwind strings | Strictly typed JSON objects |
| Security Risk | High (Requires parsing arbitrary code) | Low (Only approved components render) |
| Validation | Post-generation syntax checks | Pre-render Zod schema enforcement |
| Framework Lock-in | Tied to the generated language | Agnostic (React, Vue, Svelte, PDF) |
| Best Use Case | Rapid prototyping and boilerplate creation | Production features in existing apps |
The era of treating language models as unsupervised junior developers writing raw DOM elements is coming to a close. By enforcing a strict boundary between AI intent and UI execution, frameworks like json-render are proving that generative interfaces can be both highly dynamic and entirely predictable.
Sources: