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 }}
/>

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
styleStyleProp<ViewStyle>-Container styles

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;
}

License

MIT