Skip to main content

@myop/react-native

Official React Native bindings for embedding Myop components in your React Native applications.

Myop components are framework-agnostic UI components that can be updated in real-time without redeploying your application. Build once, embed anywhere, and iterate instantly. Perfect for teams that need to ship UI changes fast, A/B test components, or empower non-developers to customize the interface. Myop is also the safest way to adopt AI-generated components in your application—whether created by developers or non-developers—with built-in sandboxing and controlled integration.

npm version License: MIT Discord

Website | Documentation | Dashboard | Discord

Installation

npm install @myop/react-native

Install the required peer dependency:

npm install react-native-webview

Auto-Generated React Native Components

Myop automatically generates a typed React Native component package for every component you create in the dashboard. Install it directly via npm:

npm install https://cloud.myop.dev/npm/{component-id}/react-native

Then import and use it like any React Native component. For example, if you created a table component called "users-table" in the dashboard:

import { UsersTable } from "@myop/users-table";

export default function App() {
const users = [
{ id: 1, name: "Alice", email: "alice@example.com", role: "Admin" },
{ id: 2, name: "Bob", email: "bob@example.com", role: "User" },
{ id: 3, name: "Charlie", email: "charlie@example.com", role: "User" },
];

return (
<UsersTable
data={{ rows: users }}
onRowClicked={(payload) => {
console.log("Selected user:", payload.rowData);
}}
onDeleteClicked={(payload) => {
deleteUser(payload.userId);
}}
onExportRequested={(payload) => {
exportToFormat(payload.format); // "csv" | "xlsx"
}}
style={{ flex: 1 }}
/>
);
}

Why this is powerful:

  • Fully typed — The generated package includes complete TypeScript types for your component's data interface and all CTA event payloads
  • Auto loaded — Components are fetched and rendered automatically, no manual setup required
  • Not in your code — The actual component implementation lives on Myop and is loaded at runtime. Update your component in the dashboard and it's instantly live—no rebuild, no redeploy
  • Zero bundle impact — Auto-generated component packages are just thin typed wrappers. The actual component implementations are loaded at runtime via WebView, meaning your Myop components can be as complex, feature-rich, and heavy as you need without adding to your application bundle

Environment options:

Set the default environment for all components using setEnvironment:

import { setEnvironment } from "@myop/react-native";

// Set default environment for all component loads
setEnvironment("staging");

You can also override the environment directly on a specific component:

<UsersTable
data={{ rows: users }}
preview={true} // Load unpublished preview version
environment="staging" // Load from specific environment (prod, staging, etc.)
style={{ flex: 1 }}
/>

Environments are fully configurable in the dashboard, allowing you to test changes in staging before publishing to production.

For more details on auto-generated packages, see the Auto-Generated Packages documentation.

Requirements

DependencyVersion
React>= 16.8.0
React Native>= 0.60.0
react-native-webview>= 11.0.0

Quick Start

import { MyopComponent } from '@myop/react-native';

export default function App() {
return (
<MyopComponent
componentId="your-component-id"
style={{ flex: 1 }}
/>
);
}

Usage

Loading by Component ID

The simplest way to embed a Myop component:

<MyopComponent
componentId="abc123"
style={{ flex: 1 }}
/>

Passing Data to Components

Use the data prop to send data to your component's myop_init_interface:

const [userData, setUserData] = useState({ name: 'John', theme: 'dark' });

<MyopComponent
componentId="abc123"
data={userData}
style={{ flex: 1 }}
/>

When data changes, myop_init_interface is automatically called with the new value.

Handling Component Events

Listen for events from your component's myop_cta_handler:

<MyopComponent
componentId="abc123"
on={(action, payload) => {
switch (action) {
case 'submit':
handleSubmit(payload);
break;
case 'navigate':
navigation.navigate(payload.screen);
break;
}
}}
style={{ flex: 1 }}
/>

Component Proxy API

Access the component instance for direct manipulation:

import { IMyopComponentProxy } from '@myop/react-native';

const [component, setComponent] = useState<IMyopComponentProxy | null>(null);

<MyopComponent
componentId="abc123"
onLoad={(proxy) => setComponent(proxy)}
style={{ flex: 1 }}
/>

// Send data to component
component?.props.myop_init_interface({ theme: 'dark' });

// DOM manipulation
component?.element.style.set('opacity', '0.5');
component?.element.set('style.background', 'red');

// Get values (async)
const opacity = await component?.element.style.get('opacity');
const scrollTop = await component?.element.get('scrollTop');

// Lifecycle methods
component?.hide();
component?.show();
component?.dispose();

Loading & Error States

By default, no loader is shown while the component loads. The Myop-branded fallback is displayed automatically on error.

Using the Default Myop Loader

import { MyopComponent, MyopLoader } from '@myop/react-native';

<MyopComponent
componentId="abc123"
loader={<MyopLoader />} // Opt-in to default Myop loader
fadeDuration={300}
style={{ flex: 1 }}
/>

Custom Loading State

Provide your own loading component:

import { ActivityIndicator, View } from 'react-native';

<MyopComponent
componentId="abc123"
loader={
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
}
fadeDuration={300}
style={{ flex: 1 }}
/>

Custom Error Fallback

Display a custom view when the component fails to load:

import { MyopComponent, MyopFallback } from '@myop/react-native';

<MyopComponent
componentId="abc123"
fallback={
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Unable to load component</Text>
</View>
}
onError={(error) => console.error('Load failed:', error)}
style={{ flex: 1 }}
/>

// Or use the default Myop fallback explicitly
<MyopComponent
componentId="abc123"
fallback={<MyopFallback />}
style={{ flex: 1 }}
/>

Using Component Configuration

For advanced use cases, pass a full configuration object:

import { MyopComponent, IComponentInstanceConfig } from '@myop/react-native';

const config: IComponentInstanceConfig = {
id: 'instance-1',
componentId: 'abc123',
componentName: 'MyComponent',
skinSelector: {
type: 'Dedicated',
skin: { id: 'skin-1' }
}
};

<MyopComponent
componentConfig={config}
style={{ flex: 1 }}
/>

Environment Selection

Target different deployment environments:

<MyopComponent
componentId="abc123"
environment="staging" // defaults to "production"
style={{ flex: 1 }}
/>

WebView Behavior

Control scroll, zoom, and text selection:

<MyopComponent
componentId="abc123"
scrollEnabled={true} // Enable scrolling (default: false)
zoomEnabled={true} // Enable pinch-to-zoom (default: false)
selectionEnabled={true} // Enable text selection (default: false)
style={{ flex: 1 }}
/>

Pass through any other react-native-webview prop via webViewProps — for example, to debug the screen with Safari/Chrome DevTools:

<MyopComponent
componentId="abc123"
webViewProps={{ webviewDebuggingEnabled: true }}
style={{ flex: 1 }}
/>

Crash Recovery

The OS can kill the WebView renderer process under memory pressure (Android onRenderProcessGone) or for similar reasons on iOS (onContentProcessDidTerminate). MyopComponent detects these crashes and automatically remounts a fresh WebView, up to maxCrashRetries consecutive crashes per mount (default 3). After the cap, the fallback is shown instead.

<MyopComponent
componentId="abc123"
maxCrashRetries={3}
onCrash={(info) => {
console.warn(`Myop renderer crashed: ${info.reason} (attempt ${info.attempt})`);
// Return `false` to opt out of auto-recovery and show the fallback instead.
// Return nothing (or `true`) to let MyopComponent remount.
}}
style={{ flex: 1 }}
/>

The onCrash callback receives a MyopCrashInfo object:

FieldTypeDescription
reason'renderer-gone' | 'process-terminated' | 'unknown'renderer-gone = Android, process-terminated = iOS
attemptnumber1-based crash count within the current mount
willAutoRecoverbooleanfalse once the retry cap has been hit
nativeanyRaw native event payload, when available

Imperative ref API

MyopComponent accepts a ref of type MyopComponentRef:

import { useRef } from 'react';
import { MyopComponent, MyopComponentRef } from '@myop/react-native';

const ref = useRef<MyopComponentRef>(null);

<MyopComponent ref={ref} componentId="abc123" style={{ flex: 1 }} />

// Force a remount (counts toward the retry cap)
ref.current?.reload();

// Clear the crash counter and remount fresh
ref.current?.reset();

reload() is useful for retry UIs ("Tap to retry" buttons). reset() is what you typically call after the fallback has been shown — for example, when the user navigates back to the screen.

Note: onContentProcessDidTerminate and onRenderProcessGone are owned by MyopComponent and cannot be overridden via webViewProps. Use onCrash instead.

Preloading Components

Preload components for instant rendering when they're displayed:

import { preloadComponents, isPreloaded } from '@myop/react-native';

// Preload on app startup or before navigating
await preloadComponents(['component-1', 'component-2']);

// Check if component is preloaded
if (isPreloaded('component-1')) {
// Component will render instantly without loader
}

Configuration APIs

Configure the CloudRepository for custom endpoints or local development:

import {
enableLocalDev,
setCloudRepositoryUrl,
setCloudRepository,
setEnvironment,
getCloudRepository
} from '@myop/react-native';

// Enable local development mode (connects to localhost:9292)
enableLocalDev();

// Use a custom endpoint
setCloudRepositoryUrl('https://custom.myop.dev');

// Set default environment for all components
setEnvironment('staging');

// Get the current CloudRepository instance
const repo = getCloudRepository();

API Reference

MyopComponent Props

PropTypeDefaultDescription
componentIdstring-Component ID to load from Myop cloud
componentConfigIComponentInstanceConfig-Full component configuration object
dataany-Data passed to myop_init_interface
on(action: string, payload?: any) => void-Handler for myop_cta_handler events
onLoad(proxy: IMyopComponentProxy) => void-Callback with component proxy when loaded
onError(error: string) => void-Callback when component fails to load
loaderReactNodenullLoading component (default: no loader). Use <MyopLoader /> for default Myop loader
fallbackReactNode<MyopFallback />Error fallback component (default: Myop-branded fallback)
fadeDurationnumber200Loader fade-out duration in ms
environmentstring"production"Target environment
previewbooleanfalseLoad preview version of component
scrollEnabledbooleanfalseEnable WebView scrolling
zoomEnabledbooleanfalseEnable pinch-to-zoom
selectionEnabledbooleanfalseEnable text selection
webViewPropsWebViewProps-Extra props forwarded to the underlying <WebView> (e.g. { webviewDebuggingEnabled: true }). Controlled props (ref, source, onMessage, onRenderProcessGone, onContentProcessDidTerminate) can't be overridden
onCrash(info: MyopCrashInfo) => boolean | void-Called when the WebView renderer is killed by the OS. Return false to opt out of auto-recovery
maxCrashRetriesnumber3Max consecutive renderer crashes to auto-recover from per mount
styleStyleProp<ViewStyle>-Container styles

Plus an imperative ref of type MyopComponentRef with reload() and reset() methods (see Crash Recovery).

Either componentId or componentConfig must be provided.

Exported Components

ComponentDescription
MyopComponentMain component for embedding Myop content
MyopLoaderDefault animated loading state
MyopFallbackDefault error/fallback state

Exported Functions

FunctionDescription
preloadComponents(ids, env?, preview?)Preload components for instant rendering
isPreloaded(componentId, env?, preview?)Check if a component is cached
enableLocalDev()Enable local development mode (localhost:9292)
setCloudRepositoryUrl(url)Set a custom CloudRepository URL
setCloudRepository(repository)Set a custom CloudRepository instance
setEnvironment(env)Set the default environment
getCloudRepository()Get the current CloudRepository instance

Types

interface IMyopComponentProxy {
id: string;
props: {
myop_init_interface: (data: any) => void;
myop_cta_handler: ((action: string, payload?: any) => void) | null;
};
element: IElementProxy;
dispose: () => void;
hide: () => void;
show: () => void;
inspect: () => void;
}

interface IElementProxy {
set: (path: string, value: any) => void;
get: (path: string) => Promise<any>;
style: {
set: (property: string, value: string) => void;
get: (property: string) => Promise<string>;
};
}

interface IComponentInstanceConfig {
id: string;
componentId: string;
componentName: string;
skinSelector: ISkinSelectorConfig;
nestedComponents?: IComponentInstanceConfig[];
resolvedExperiences?: IExperience[];
resolvedNestedComponents?: IComponentConfig[];
[key: string]: any;
}

interface MyopLoaderRef {
fadeOut: (duration?: number) => void;
}

interface MyopCrashInfo {
reason: 'renderer-gone' | 'process-terminated' | 'unknown';
attempt: number;
willAutoRecover: boolean;
native?: any;
}

interface MyopComponentRef {
reload: () => void;
reset: () => void;
}

License

MIT