Copy for LLM View Markdown Export generated UI as standalone code for your framework.
While json-render is designed for dynamic rendering, you can export generated UI as static code. The code generation is intentionally project-specific so you have full control over:
Component templates (standalone, no json-render dependencies)
Package.json and project structure
Framework-specific patterns (Next.js, Remix, etc.)
How data is passed to components
Code export is split into two parts:
Framework-agnostic utilities for building code generators:
import {
traverseSpec , // Walk the UI spec
collectUsedComponents , // Get all component types used
collectStatePaths , // Get all data binding paths
collectActions , // Get all action names
serializeProps , // Convert props to JSX string
} from ' @json-render/codegen ' ;
Custom code generator specific to your project and framework:
// lib/codegen/generator.ts
import { collectUsedComponents , serializeProps } from ' @json-render/codegen ' ;
export function generateNextJSProject ( spec : Spec ) : GeneratedFile [] {
const components = collectUsedComponents (spec) ;
return [
{ path : ' package.json ' , content : ' ... ' },
{ path : ' app/page.tsx ' , content : ' ... ' },
// ... component files
] ;
}
See the dashboard example for a complete implementation that exports:
package.json - Dependencies and scripts
tsconfig.json - TypeScript config
next.config.js - Next.js config
app/layout.tsx - Root layout
app/globals.css - Global styles
app/page.tsx - Generated page with data
components/ui/*.tsx - Standalone components
The exported components are standalone with no json-render dependencies. They receive data as props instead of using hooks:
// Generated component (standalone)
interface MetricProps {
label : string ;
statePath : string ;
data ?: Record < string , unknown >;
}
export function Metric ({ label , statePath , data } : MetricProps ) {
const value = data ? getByPath (data , statePath) : undefined ;
return (
< div >
< span > { label } </ span >
< span > { formatValue (value) } </ span >
</ div >
) ;
}
import { traverseSpec } from ' @json-render/codegen ' ;
traverseSpec (spec , ( element , key , depth , parent ) => {
console . log ( ' ' . repeat (depth * 2 ) + `${ key } : ${ element . type }` ) ;
} ) ;
import { collectUsedComponents } from ' @json-render/codegen ' ;
const components = collectUsedComponents (spec) ;
// Set { 'Card', 'Metric', 'Chart', 'Table' }
// Generate only the needed component files
for ( const component of components) {
files . push ( {
path : ` components/ui/ ${ component . toLowerCase () } .tsx ` ,
content : componentTemplates[component] ,
} ) ;
}
import { serializeProps } from ' @json-render/codegen ' ;
const propsStr = serializeProps ( {
title : ' Dashboard ' ,
columns : 3 ,
disabled : true ,
} ) ;
// 'title="Dashboard" columns={3} disabled'
Run the dashboard example and click "Export Project" to see code generation in action:
cd examples/dashboard
pnpm dev
# Open http://dashboard-demo.json-render.localhost:1355
# Generate a widget, then click "Export Project"