@servlyadmin/runtime-react
React wrapper for Servly runtime renderer. Render Servly components in your React applications with full support for props, slots, and event handling.
Installation
npm install @servlyadmin/runtime-react @servlyadmin/runtime-core
yarn add @servlyadmin/runtime-react @servlyadmin/runtime-core
pnpm add @servlyadmin/runtime-react @servlyadmin/runtime-core
Quick Start
import { ServlyComponent } from '@servlyadmin/runtime-react';
function App() {
return (
<ServlyComponent
id="my-component"
version="latest"
props={{ title: 'Hello World' }}
/>
);
}
Props
id | string | required | Component ID from the registry |
version | string | 'latest' | Version specifier |
props | object | {} | Props to pass to the component |
slots | Record<string, ReactNode> | - | Slot content |
fallback | ReactNode | - | Loading/error fallback |
onError | (error: Error) => void | - | Error callback |
onLoad | () => void | - | Load complete callback |
className | string | - | Wrapper class name |
style | CSSProperties | - | Wrapper styles |
showSkeleton | boolean | true | Show loading skeleton |
cacheStrategy | CacheStrategy | 'memory' | Cache strategy |
eventHandlers | object | - | Event handlers by element ID |
children | ReactNode | - | Default slot content |
Usage Examples
Basic Usage
import { ServlyComponent } from '@servlyadmin/runtime-react';
function MyPage() {
return (
<ServlyComponent
id="hero-section"
props={{
title: 'Welcome',
subtitle: 'Get started today',
}}
/>
);
}
With Slots
function CardExample() {
return (
<ServlyComponent
id="card-component"
slots={{
header: <h2>Card Title</h2>,
footer: <button>Learn More</button>,
}}
>
{/* Children go to default slot */}
<p>This is the card content.</p>
</ServlyComponent>
);
}
With Event Handlers
function InteractiveExample() {
const [count, setCount] = useState(0);
return (
<ServlyComponent
id="counter-component"
props={{ count }}
eventHandlers={{
'increment-btn': {
click: () => setCount(c => c + 1),
},
'decrement-btn': {
click: () => setCount(c => c - 1),
},
}}
/>
);
}
Loading States
function WithLoadingState() {
return (
<ServlyComponent
id="data-component"
fallback={<div>Loading...</div>}
onLoad={() => console.log('Component loaded!')}
onError={(error) => console.error('Failed to load:', error)}
/>
);
}
Custom Loading Skeleton
function WithCustomSkeleton() {
return (
<ServlyComponent
id="profile-card"
showSkeleton={false}
fallback={
<div className="animate-pulse">
<div className="h-32 bg-gray-200 rounded" />
<div className="h-4 bg-gray-200 rounded mt-4 w-3/4" />
</div>
}
/>
);
}
Version Pinning
function VersionedComponent() {
return (
<>
{/* Exact version */}
<ServlyComponent id="my-component" version="1.2.3" />
{/* Version range */}
<ServlyComponent id="my-component" version="^1.0.0" />
{/* Latest */}
<ServlyComponent id="my-component" version="latest" />
</>
);
}
Cache Control
function CacheExample() {
return (
<>
{/* Memory cache (default) */}
<ServlyComponent id="comp1" cacheStrategy="memory" />
{/* Persist to localStorage */}
<ServlyComponent id="comp2" cacheStrategy="localStorage" />
{/* No caching */}
<ServlyComponent id="comp3" cacheStrategy="none" />
</>
);
}
Dynamic Props
function DynamicPropsExample() {
const [theme, setTheme] = useState('light');
const [user, setUser] = useState({ name: 'Guest' });
return (
<ServlyComponent
id="themed-component"
props={{
theme,
userName: user.name,
timestamp: Date.now(),
}}
/>
);
}
Error Boundary Integration
import { ErrorBoundary } from 'react-error-boundary';
function SafeComponent() {
return (
<ErrorBoundary fallback={<div>Something went wrong</div>}>
<ServlyComponent
id="risky-component"
onError={(error) => {
// Log to error tracking service
logError(error);
}}
/>
</ErrorBoundary>
);
}
TypeScript
Full TypeScript support:
import { ServlyComponent, type ServlyComponentProps } from '@servlyadmin/runtime-react';
interface MyComponentProps {
title: string;
count: number;
}
function TypedExample() {
return (
<ServlyComponent<MyComponentProps>
id="typed-component"
props={{
title: 'Hello',
count: 42,
}}
/>
);
}
Server-Side Rendering
The component handles SSR gracefully by rendering the fallback on the server and hydrating on the client.
function SSRPage() {
return (
<ServlyComponent
id="ssr-component"
fallback={<div>Loading component...</div>}
/>
);
}
Performance Tips
- Use version pinning in production to leverage caching
- Prefetch components that will be needed soon
- Use
cacheStrategy="localStorage" for components that rarely change
- Memoize event handlers to prevent unnecessary re-renders
import { useMemo, useCallback } from 'react';
function OptimizedExample() {
const eventHandlers = useMemo(() => ({
'btn': {
click: () => console.log('clicked'),
},
}), []);
return (
<ServlyComponent
id="optimized"
eventHandlers={eventHandlers}
/>
);
}
License
MIT