SuperAtom Runtime SDK - React components for rendering JSON UI schemas
npm install @superatomai/renderer-reactReact components for rendering JSON UI schemas from SuperAtom responses.
- Installation
- Quick Start
- API Reference
- Available Components
- Dynamic Component Loading from Bundles
- JSON Schema Structure
- Advanced Usage
- TypeScript Support
- Development
``bash`
pnpm add @superatomai/renderer-reactor
npm install @superatomai/renderer-reactor
yarn add @superatomai/renderer-react
This package requires React 18+:
`bash`
pnpm add react react-dom
`tsx
import { useState } from 'react';
import { DSLRenderer } from '@superatomai/renderer-react';
function DashboardPanel() {
const [uiSchema, setUiSchema] = useState(null);
const [uiData, setUiData] = useState(null);
const handleRenderUI = (schema: any, data: any) => {
setUiSchema(schema);
setUiData(data || {});
};
return (
export default DashboardPanel;
`
`tsx
import { useState } from 'react';
import { DSLRenderer } from '@superatomai/renderer-react';
function ReportGenerator() {
const [reports, setReports] = useState([]);
const addReport = (schema: any, data: any) => {
setReports(prev => [...prev, {
id: Date.now(),
schema,
data: data || {}
}]);
};
return (
$3
`tsx
import { useState } from 'react';
import { DSLRenderer } from '@superatomai/renderer-react';interface DashboardPanel {
id: string;
title: string;
schema: any;
data: any;
}
function Dashboard() {
const [panels, setPanels] = useState([]);
const addPanel = (title: string, schema: any, data: any) => {
setPanels(prev => [...prev, {
id:
panel-${Date.now()},
title,
schema,
data
}]);
}; return (
{panels.map(panel => (
{panel.title}
dsl={panel.schema}
data={panel.data}
/>
))}
);
}
`API Reference
$3
Main component for rendering JSON UI schemas.
#### Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
|
dsl | UIComponent | Yes | The UI schema to render |
| data | Record | No | Data context for the UI |
| context | Record | No | Additional context variables |
| handlers | Record | No | Event handlers for components |
| onNavigate | (uiid: string, params?: Record | No | Navigation handler |$3
####
COMP_REGISTRYGlobal registry containing all available components (both native and dynamically loaded).
`typescript
import { COMP_REGISTRY } from '@superatomai/renderer-react';// Access the registry
console.log(Object.keys(COMP_REGISTRY)); // ['COMP_ECHART', 'COMP_AGGRID', ...]
`####
getComponentStates()Returns the current state of all components.
`typescript
import { getComponentStates } from '@superatomai/renderer-react';const states = getComponentStates();
// Returns: { loaded: string[], loading: string[], failed: string[] }
`####
resetFailedComponent(componentId: string)Resets the failed state of a specific component, allowing it to be retried.
`typescript
import { resetFailedComponent } from '@superatomai/renderer-react';resetFailedComponent('echarts'); // Allows echarts to be loaded again
`####
resetAllFailedComponents()Resets all failed components.
`typescript
import { resetAllFailedComponents } from '@superatomai/renderer-react';const count = resetAllFailedComponents(); // Returns number of components reset
`####
Low-level component for rendering registry components directly (rarely needed).
`typescript
import { DynamicComponent } from '@superatomai/renderer-react'; type="COMP_ECHART"
props={{ option: {...} }}
/>
`#### Example
`tsx
dsl={{
id: 'chart-component',
name: 'ChartComponent',
data: { chartData: [...] },
render: {
id: 'render-root',
type: 'COMP_ECHART',
props: {
option: { $bind: 'chartData' }
}
}
}}
data={{ chartData: [...] }}
handlers={{
onChartClick: (params) => console.log('Chart clicked', params)
}}
/>
`Available Components
The SDK includes the following native components:
- COMP_ECHART - ECharts for data visualization
- COMP_AGGRID - AG Grid for data tables
- COMP_HANDSONTABLE - Handsontable for spreadsheets
- COMP_LEAFLET - Leaflet for maps
- COMP_MAPBOX - Mapbox GL for advanced maps
- COMP_VIS_NETWORK - Network/graph visualizations
- COMP_THREE_SCENE - 3D visualizations with Three.js
- COMP_PDF_VIEWER - PDF document viewer
- COMP_LUCKYSHEET - Excel-like spreadsheet
- COMP_MARKDOWN - Markdown renderer
- COMP_ICONIFY_ICON - Icon library
Dynamic Component Loading from Bundles
This package supports automatic registration of custom components from external bundles. This allows you to build your own components separately, bundle them, and have them automatically loaded into the component registry at runtime.
$3
1. Package Initialization: When you import
@superatomai/renderer-react, it automatically:
- Sets up an event listener for component loading
- Exposes window.runtime.componentsLoaded() for bundles to call
- Watches window.SUPERATOM.COMPONENTS for new components2. Bundle Setup: Your bundle calls
setup() from @superatomai/sdk-web and triggers the event
3. Auto-Registration: Components are wrapped and registered in COMP_REGISTRY with keys like COMP_YourComponent$3
Step 1: Define Your Components
`typescript
// src/components/DynamicBarChart.tsx
export default function DynamicBarChart({ data, config }) {
return (
{/ Your custom bar chart implementation /}
);
}
`Step 2: Setup Bundle Entry Point
`typescript
// src/superatom.ts
import { createRoot } from 'react-dom/client';
import { createElement } from 'react';
import { setup } from '@superatomai/sdk-web';
import DynamicBarChart from './components/DynamicBarChart';
import DynamicDataTable from './components/DynamicDataTable';const COMPONENTS = {
DynamicBarChart,
DynamicDataTable,
// Add your other components...
// REQUIRED: mount function for React version isolation
mount: (Component, container, props) => {
// Use the bundle's own React instance to create a root
const root = createRoot(container);
root.render(createElement(Component, props));
return { unmount: () => root.unmount() };
}
};
const SUPERATOM = {
init: async () => {
// Register components with setup()
setup(COMPONENTS);
// Trigger component registration event
(window as any).runtime?.componentsLoaded();
// Send metadata to SDK if needed
const sdkClient = (window as any).SA_WEB_SDK_CLIENT;
if (sdkClient) {
sdkClient.sendComponents(componentsMetadata);
}
},
destroy: () => {
// Cleanup if needed
}
};
export default SUPERATOM;
`> Important: The
mount function is required for React version isolation. It ensures your bundle's React instance is used to render components, preventing version conflicts with the host application.Step 3: Build Your Bundle
Use your preferred bundler (Vite, Webpack, etc.) to create a UMD or IIFE bundle that exposes
SUPERATOM globally.$3
Option 1: Load Bundle Script Dynamically
`tsx
import { useEffect, useState } from 'react';
import { DSLRenderer } from '@superatomai/renderer-react';function App() {
const [bundleLoaded, setBundleLoaded] = useState(false);
useEffect(() => {
// Load bundle script
const script = document.createElement('script');
script.src = 'https://your-cdn.com/bundle.js';
script.onload = () => {
// Initialize bundle after package is ready
if (window.SUPERATOM?.init) {
window.SUPERATOM.init().then(() => {
setBundleLoaded(true);
});
}
};
document.head.appendChild(script);
}, []);
return (
{bundleLoaded ? (
dsl={{
id: 'custom-chart',
render: {
id: 'chart-root',
type: 'COMP_DynamicBarChart', // Your custom component
props: {
data: { $bind: 'chartData' }
}
}
}}
data={{ chartData: [...] }}
/>
) : (
Loading components...
)}
);
}
`Option 2: Static Script Tag
`html
`$3
⚠️ Loading Order: The npm package must be imported BEFORE calling
window.SUPERATOM.init(), otherwise the event listener won't be set up yet.✅ Best Practice Pattern:
`typescript
// 1. Import package (sets up event listeners)
import { DSLRenderer } from '@superatomai/renderer-react';// 2. Load bundle script
// 3. Call SUPERATOM.init() after both are ready
// 4. Render components
`$3
Once your bundle is loaded and initialized, components are automatically registered with the
COMP_ prefix:`json
{
"id": "my-ui",
"render": {
"id": "root",
"type": "COMP_DynamicBarChart",
"props": {
"data": { "$bind": "salesData" },
"config": {
"title": "Sales by Region"
}
}
}
}
`$3
`typescript
import { getComponentStates } from '@superatomai/renderer-react';// Check component loading status
const states = getComponentStates();
console.log('Loaded components:', states.loaded);
console.log('Loading components:', states.loading);
console.log('Failed components:', states.failed);
// Access the registry directly (for debugging)
console.log('Available components:', window.COMP_REGISTRY);
`$3
Bundle components are automatically wrapped with
BundleComponentWrapper to ensure React version isolation. This means:- Your bundle can use its own version of React
- The wrapper ensures proper rendering in the host application's React tree
- Each component has isolated error boundaries
JSON Schema Structure
$3
`typescript
{
id: string; // Unique component ID
name?: string; // Component name
props?: Record; // Component props
states?: Record; // Component state
data?: Record; // Component data
render: UIElement; // Root UI element to render
}
`$3
`typescript
{
id: string; // Unique element ID
type: string; // Element type (div, span, COMP_*)
props?: Record; // Element props
children?: UIElement[] | string; // Child elements // Conditional rendering
if?: { $exp: string };
else?: UIElement;
// Loop rendering
for?: {
in: { $bind: string } | { $exp: string };
as: string;
key?: string;
index?: string;
};
// Data binding
// Use { $bind: 'data.path' } for data binding
// Use { $exp: 'expression' } for expressions
}
`$3
`json
{
"id": "sales-dashboard",
"name": "SalesDashboard",
"data": {
"salesData": [
{ "region": "North", "sales": 1000 },
{ "region": "South", "sales": 1500 }
]
},
"render": {
"id": "root",
"type": "div",
"props": {
"style": { "padding": "20px" }
},
"children": [
{
"id": "title",
"type": "h1",
"children": "Sales Dashboard"
},
{
"id": "chart",
"type": "COMP_ECHART",
"props": {
"option": {
"xAxis": {
"type": "category",
"data": { "$exp": "salesData.map(d => d.region)" }
},
"yAxis": { "type": "value" },
"series": [{
"type": "bar",
"data": { "$exp": "salesData.map(d => d.sales)" }
}]
},
"style": { "height": "400px" }
}
}
]
}
}
`Advanced Usage
$3
`tsx
dsl={schema}
data={data}
handlers={{
onRowClick: (row) => {
console.log('Row clicked:', row);
// Handle row click
},
onFilterChange: (filters) => {
console.log('Filters changed:', filters);
// Update filters
}
}}
/>
`$3
`tsx
dsl={schema}
data={data}
onNavigate={(uiid, params) => {
console.log('Navigate to:', uiid, 'with params:', params);
// Load new UI based on uiid
loadUI(uiid, params);
}}
/>
`$3
`tsx
import { DSLErrorBoundary } from '@superatomai/renderer-react';function App() {
return (
);
}
`$3
`tsx
import { getComponentStates, resetFailedComponent } from '@superatomai/renderer-react';// Check which components are loaded
const states = getComponentStates();
console.log('Loaded:', states.loaded);
console.log('Failed:', states.failed);
// Reset a failed component to retry loading
resetFailedComponent('echarts');
`TypeScript Support
Full TypeScript support with type definitions:
`tsx
import type {
UIComponent,
UIElement,
DSLRendererProps
} from '@superatomai/renderer-react';const schema: UIComponent = {
id: 'my-component',
render: {
id: 'root',
type: 'div',
children: 'Hello World'
}
};
`Development
`bash
Install dependencies
pnpm installBuild the package
pnpm buildWatch mode for development
pnpm devType checking
pnpm typecheck
``MIT
For issues and questions:
- GitHub Issues: superatom/sdk-runtime
- Documentation: docs.superatom.ai