import Link from "next/link"; import { Code } from "@/components/code"; export const metadata = { title: "Registry | json-render", }; export default function RegistryPage() { return (

Registry

Register React components and action handlers to bring your catalog to life.

{/* Components Section */}

Component Registry

Create a registry that maps catalog component types to React components:

{`import { useAction } from '@json-render/react'; const registry = { Card: ({ props, children }) => (

{props.title}

{props.description &&

{props.description}

} {children}
), Button: ({ props }) => { const executeAction = useAction(props.action); return ( ); }, };`}

Component Props

Each component receives these props:

{`interface ComponentProps> { props: T; // Component props from the spec children?: React.ReactNode; // Rendered children (for slot components) } // Type-safe props by extracting from your catalog type CardProps = ComponentProps<{ title: string; description: string | null; }>; // Use hooks for actions and data within components import { useAction, useDataValue } from '@json-render/react';`}

Using Data Binding

Use hooks to read and write data:

{`import { useDataValue, useDataBinding } from '@json-render/react'; const Metric = ({ props }) => { // Read-only value from data context const value = useDataValue(props.valuePath); return (
{props.label} {formatValue(value)}
); }; const TextField = ({ props }) => { // Two-way binding to data context const [value, setValue] = useDataBinding(props.valuePath); return ( setValue(e.target.value)} placeholder={props.placeholder} /> ); };`}
{/* Actions Section */}

Action Handlers

Instead of AI generating arbitrary code, it declares intent by name. Your application provides the implementation. This is a core guardrail.

Defining Actions

Define available actions in your catalog:

{`import { defineCatalog } from '@json-render/core'; import { schema } from '@json-render/react'; import { z } from 'zod'; const catalog = defineCatalog(schema, { components: { /* ... */ }, actions: { submit_form: { params: z.object({ formId: z.string(), }), description: 'Submit a form', }, export_data: { params: z.object({ format: z.enum(['csv', 'pdf', 'json']), filters: z.object({ dateRange: z.string().nullable(), }).nullable(), }), }, navigate: { params: z.object({ url: z.string(), }), }, }, });`}

ActionProvider

Provide action handlers to your app:

{`import { ActionProvider } from '@json-render/react'; function App() { const handlers = { submit_form: async (params) => { const response = await fetch('/api/submit', { method: 'POST', body: JSON.stringify({ formId: params.formId }), }); return response.json(); }, export_data: async (params) => { const blob = await generateExport(params.format, params.filters); downloadBlob(blob, \`export.\${params.format}\`); }, navigate: (params) => { window.location.href = params.url; }, }; return ( {/* Your UI */} ); }`}

Using Actions in Components

{`import { useAction } from '@json-render/react'; // Using the useAction hook (recommended) const Button = ({ props }) => { const executeAction = useAction(props.action); return ( ); }; // Or for standalone use function SubmitButton() { const submitForm = useAction('submit_form'); return ( ); }`} {/* Renderer Section */}

Using the Renderer

{`import { Renderer, ActionProvider } from '@json-render/react'; function App() { return ( ); }`}

Next

Learn about{" "} data binding {" "} for dynamic values.

); }