Rendering Pages

Render UI Builder pages in production using the LayerRenderer component. Display your designed pages without the editor interface, with full support for dynamic content through variables.

Basic Rendering Demo
Variables Demo

Basic Usage

Use the LayerRenderer component to display UI Builder pages without the editor interface:

tsx
1import LayerRenderer from '@/components/ui/ui-builder/layer-renderer'; 2import { ComponentLayer, ComponentRegistry } from '@/components/ui/ui-builder/types'; 3 4// Your component registry (same as used in UIBuilder) 5const myComponentRegistry: ComponentRegistry = { 6 // Your component definitions... 7}; 8 9// Page data from UIBuilder or database 10const page: ComponentLayer = { 11 id: "welcome-page", 12 type: "div", 13 name: "Welcome Page", 14 props: { 15 className: "p-6 max-w-4xl mx-auto" 16 }, 17 children: [ 18 { 19 id: "title", 20 type: "h1", 21 name: "Title", 22 props: { 23 className: "text-3xl font-bold mb-4" 24 }, 25 children: "Welcome to My App" 26 }, 27 { 28 id: "description", 29 type: "p", 30 name: "Description", 31 props: { 32 className: "text-gray-600" 33 }, 34 children: "This page was built with UI Builder." 35 } 36 ] 37}; 38 39function MyRenderedPage() { 40 return ( 41 <LayerRenderer 42 page={page} 43 componentRegistry={myComponentRegistry} 44 /> 45 ); 46}

Rendering with Variables

Make your pages dynamic by binding component properties to variables:

tsx
1import LayerRenderer from '@/components/ui/ui-builder/layer-renderer'; 2import { Variable } from '@/components/ui/ui-builder/types'; 3 4// Define your variables 5const variables: Variable[] = [ 6 { 7 id: "userName", 8 name: "User Name", 9 type: "string", 10 defaultValue: "Guest" 11 }, 12 { 13 id: "userAge", 14 name: "User Age", 15 type: "number", 16 defaultValue: 25 17 }, 18 { 19 id: "showWelcomeMessage", 20 name: "Show Welcome Message", 21 type: "boolean", 22 defaultValue: true 23 } 24]; 25 26// Page with variable bindings (created in UIBuilder) 27const pageWithVariables: ComponentLayer = { 28 id: "user-profile", 29 type: "div", 30 props: { 31 className: "p-6 bg-white rounded-lg shadow" 32 }, 33 children: [ 34 { 35 id: "welcome-message", 36 type: "h2", 37 props: { 38 className: "text-2xl font-bold mb-2", 39 children: { __variableRef: "userName" } // Bound to userName variable 40 }, 41 children: [] 42 }, 43 { 44 id: "age-display", 45 type: "p", 46 props: { 47 className: "text-gray-600", 48 children: { __variableRef: "userAge" } // Bound to userAge variable 49 }, 50 children: [] 51 } 52 ] 53}; 54 55// Provide runtime values for variables 56const variableValues = { 57 userName: "Jane Smith", 58 userAge: 28, 59 showWelcomeMessage: true 60}; 61 62function DynamicUserProfile() { 63 return ( 64 <LayerRenderer 65 page={pageWithVariables} 66 componentRegistry={myComponentRegistry} 67 variables={variables} 68 variableValues={variableValues} 69 /> 70 ); 71}

Production Integration

Integrate with your data sources to create personalized experiences:

tsx
1function CustomerPage({ customerId }: { customerId: string }) { 2 const [pageData, setPageData] = useState<ComponentLayer | null>(null); 3 const [customerData, setCustomerData] = useState({}); 4 5 useEffect(() => { 6 async function loadData() { 7 // Load page structure from your CMS/database 8 const pageResponse = await fetch('/api/pages/customer-dashboard'); 9 const page = await pageResponse.json(); 10 11 // Load customer-specific data 12 const customerResponse = await fetch(`/api/customers/${customerId}`); 13 const customer = await customerResponse.json(); 14 15 setPageData(page); 16 setCustomerData(customer); 17 } 18 19 loadData(); 20 }, [customerId]); 21 22 if (!pageData) return <div>Loading...</div>; 23 24 return ( 25 <LayerRenderer 26 page={pageData} 27 componentRegistry={myComponentRegistry} 28 variables={variables} 29 variableValues={{ 30 customerName: customerData.name, 31 companyLogo: customerData.logoUrl, 32 brandColor: customerData.primaryColor, 33 // Inject real customer data into the template 34 }} 35 /> 36 ); 37}

Performance Optimization

Optimize rendering performance for production:

tsx
1// Memoize the renderer to prevent unnecessary re-renders 2const MemoizedRenderer = React.memo(LayerRenderer, (prevProps, nextProps) => { 3 return ( 4 prevProps.page === nextProps.page && 5 JSON.stringify(prevProps.variableValues) === JSON.stringify(nextProps.variableValues) 6 ); 7}); 8 9// Use in your component 10function OptimizedPage() { 11 return ( 12 <MemoizedRenderer 13 page={page} 14 componentRegistry={myComponentRegistry} 15 variables={variables} 16 variableValues={variableValues} 17 /> 18 ); 19}

Error Handling

Handle rendering errors gracefully in production:

tsx
1import { ErrorBoundary } from 'react-error-boundary'; 2 3function ErrorFallback({ error }: { error: Error }) { 4 return ( 5 <div className="p-4 bg-red-50 border border-red-200 rounded"> 6 <h2 className="text-lg font-semibold text-red-800">Page failed to load</h2> 7 <p className="text-red-600">{error.message}</p> 8 <button 9 onClick={() => window.location.reload()} 10 className="mt-2 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700" 11 > 12 Reload Page 13 </button> 14 </div> 15 ); 16} 17 18function SafeRenderedPage() { 19 return ( 20 <ErrorBoundary FallbackComponent={ErrorFallback}> 21 <LayerRenderer 22 page={page} 23 componentRegistry={myComponentRegistry} 24 variables={variables} 25 variableValues={variableValues} 26 /> 27 </ErrorBoundary> 28 ); 29}

LayerRenderer Props

  • page (required): The ComponentLayer to render
  • componentRegistry (required): Registry mapping component types to their definitions
  • className: Optional CSS class for the root container
  • variables: Array of Variable definitions available for binding
  • variableValues: Object mapping variable IDs to runtime values (overrides defaults)
  • editorConfig: Internal editor configuration (rarely needed in production)

Best Practices

  1. Use the same componentRegistry in both UIBuilder and LayerRenderer
  2. Validate variable values before passing to LayerRenderer to prevent runtime errors
  3. Handle loading states while fetching page data and variables
  4. Implement error boundaries to gracefully handle rendering failures
  5. Cache page data when possible for better performance
  6. Memoize expensive variable calculations to avoid unnecessary re-computations
  7. Test variable bindings thoroughly to ensure robustness across different data scenarios