Paths follow JSON Pointer (RFC 6901) into the spec object:
/root -> Root element key (string)/elements/card-1 -> Element with key "card-1"/elements/card-1/props -> Props of card-1/elements/card-1/children -> Children of card-1
For custom or framework-agnostic streaming implementations, use the SpecStream compiler from @json-render/core directly:
import { createSpecStreamCompiler } from '@json-render/core';// Create a compiler for your spec typeconst compiler = createSpecStreamCompiler<MySpec>();const decoder = new TextDecoder();// Process streaming chunks from AIasync function processStream(reader: ReadableStreamDefaultReader<Uint8Array>) { while (true) { const { done, value } = await reader.read(); if (done) break; // Decode the Uint8Array chunk to a string const chunk = decoder.decode(value, { stream: true }); const { result, newPatches } = compiler.push(chunk); if (newPatches.length > 0) { // Update UI with partial result setSpec(result); } } // Get final compiled result return compiler.getResult();}
@json-render/react provides the useUIStream hook, which wraps the low-level compiler in a React-friendly API with state management, error handling, and abort support.
import { useUIStream } from '@json-render/react';function App() { const { spec, // Current UI spec state isStreaming, // True while streaming error, // Any error that occurred send, // Function to start generation clear, // Function to reset spec and error } = useUIStream({ api: '/api/generate', onComplete: (spec) => {}, // Optional: called when streaming completes onError: (error) => {}, // Optional: called when an error occurs });}