npm package: @myop/react
Description: Official React bindings for embedding [Myop](https://myop.dev) components in your React applications.
Latest version: 0.0.48

# @myop/react

Official React bindings for embedding [Myop](https://myop.dev) components in your React 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](https://img.shields.io/npm/v/@myop/react.svg)](https://www.npmjs.com/package/@myop/react)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Discord](https://img.shields.io/badge/Discord-Join%20us-5865F2?logo=discord&logoColor=white)](https://myop.dev/discord)

[Website](https://www.myop.dev/) | [Documentation](https://docs.myop.dev/) | [Dashboard](https://dashboard.myop.dev/) | [Discord](https://myop.dev/discord)

## Installation

```bash
npm install @myop/react
```

```bash
yarn add @myop/react
```

```bash
pnpm add @myop/react
```

## Auto-Generated React Components

Myop automatically generates a typed React component package for every component you create in the [dashboard](https://dashboard.myop.dev/). Install it directly via npm:

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

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

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

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"
      }}
    />
  );
}
```

**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** — The entire `@myop/react` package costs only ~6KB gzipped—and that's the total cost whether you use 1, 2, or 1,000 components. Auto-generated component packages are just thin typed wrappers. The actual component implementations are loaded at runtime, meaning your Myop components can be as complex, feature-rich, and heavy as you need without adding a single byte to your application bundle. Consider typical bundle costs: a chart library (~60KB), a map component (~200KB), a data grid (~150KB), a rich text editor (~100KB), or a chat widget with emoji picker (~80KB). With Myop, all of these cost ~0KB to your bundle—they load on-demand when needed

**Environment options:**

Set the default environment for all components using `setEnvironment`:

```tsx
import { setEnvironment } from "@myop/react";

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

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

```tsx
<UsersTable
  data={...}
  preview={true}        // Load unpublished preview version
  environment="staging" // Load from specific environment (prod, staging, etc.)
/>
```

Environments are fully configurable in the [dashboard](https://dashboard.myop.dev/), allowing you to test changes in staging before publishing to production.

For more details on auto-generated packages, see the [Auto-Generated Packages documentation](https://docs.myop.dev/docs/learnMyop/AutoGeneratedPackages).

## Requirements

- React 18.0+

## Quick Start

```tsx
import { MyopComponent } from "@myop/react";

function App() {
  return (
    <MyopComponent
      componentId="your-component-id"
      style={{ width: 600, height: 400 }}
      on={(action, payload) => {
        console.log("Action:", action, "Payload:", payload);
      }}
    />
  );
}
```

## Components

### `MyopComponent`

The main component for embedding Myop components.

```tsx
import { MyopComponent } from "@myop/react";

<MyopComponent
  componentId="abc123"
  data={{ items: [...] }}
  onRowClicked={(payload) => console.log(payload)}
  onLoad={(component) => console.log("Loaded!", component)}
  onError={(error) => console.error(error)}
/>
```

#### Props

| Prop | Type | Description |
|------|------|-------------|
| `componentId` | `string` | The ID of the Myop component to load |
| `data` | `TData` | Data to pass to the component via `myop_init_interface` |
| `on` | `(action, payload) => void` | Generic handler for all CTA events |
| `on[ActionName]` | `(payload) => void` | Typed handler for specific actions (e.g., `onRowClicked`) |
| `onLoad` | `(component) => void` | Called when the component finishes loading |
| `onError` | `(error: string) => void` | Called when loading fails |
| `style` | `CSSProperties` | CSS styles for the container |
| `loader` | `ReactNode` | Loading indicator (default: `null` - no loader). Use `loader={<MyopLoader />}` for default Myop loader |
| `fallback` | `ReactNode` | Error fallback UI (default: `<MyopFallback />`). Override with custom component |
| `fadeDuration` | `number` | Loader fade-out duration in ms (default: `200`) |
| `environment` | `string` | Load from a specific environment (e.g., `"staging"`, `"prod"`) |
| `preview` | `boolean` | Load the unpublished preview version of the component |

#### Environments & Preview

Myop supports multiple environments, allowing you to test changes before going live:

```tsx
// Production (default)
<MyopComponent componentId="abc123" />

// Load from staging environment
<MyopComponent componentId="abc123" environment="staging" />

// Load unpublished preview version (for testing before publishing)
<MyopComponent componentId="abc123" preview={true} />

// Combine both: preview version in staging
<MyopComponent componentId="abc123" environment="staging" preview={true} />
```

Environments are configured in the [dashboard](https://dashboard.myop.dev/). Use `preview={true}` to test unpublished changes before making them live.

### `MyopContainer` (Legacy)

The legacy container component. Use `MyopComponent` for new projects.

```tsx
import { MyopContainer } from "@myop/react";

<MyopContainer
  componentId="abc123"
  onReady={(component) => console.log("Ready!", component)}
/>
```

## Type-Safe Event Handlers

Define your CTA payloads for fully typed event handlers:

```tsx
import { MyopComponent, IPropTypes } from "@myop/react";

// Define your component's data and CTA payload types
interface MyData {
  items: { id: string; name: string }[];
}

interface MyCtaPayloads {
  "row-clicked": { rowIndex: number; rowData: any };
  "item-selected": { itemId: string };
  "export-requested": { format: "csv" | "json" };
}

function Dashboard() {
  return (
    <MyopComponent<MyData, MyCtaPayloads>
      componentId="dashboard-component"
      data={{ items: [...] }}
      // Typed handler - kebab-case converts to onPascalCase
      onRowClicked={(payload) => {
        // payload is typed as { rowIndex: number; rowData: any }
        console.log("Row clicked:", payload.rowIndex);
      }}
      onItemSelected={(payload) => {
        // payload is typed as { itemId: string }
        console.log("Item selected:", payload.itemId);
      }}
      // Or use the generic handler
      on={(action, payload) => {
        // action is keyof MyCtaPayloads
        console.log(action, payload);
      }}
    />
  );
}
```

## Configuration

### Preloading Components

Preload components for faster rendering:

```tsx
import { preloadComponents, isPreloaded } from "@myop/react";

// Preload multiple components
await preloadComponents(["component-1", "component-2"]);

// Check if a component is preloaded
if (isPreloaded("component-1")) {
  console.log("Component is cached and ready");
}
```

### Custom Repository URL

```tsx
import { setCloudRepositoryUrl } from "@myop/react";

// Point to a custom Myop server
setCloudRepositoryUrl("https://your-custom-server.com");
```

### Environment Configuration

```tsx
import { setEnvironment } from "@myop/react";

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

### Local Development

```tsx
import { enableLocalDev } from "@myop/react";

// Connect to local Myop development server (localhost:9292)
enableLocalDev();
```

### Advanced: Custom Repository

```tsx
import { setCloudRepository, getCloudRepository } from "@myop/react";
import { CloudRepository } from "@myop/sdk/helpers";

// Set a custom CloudRepository instance
const customRepo = new CloudRepository("https://custom-url.com");
setCloudRepository(customRepo);

// Get the current repository
const repo = getCloudRepository();
```

## 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

```tsx
import { MyopComponent, MyopLoader } from "@myop/react";

<MyopComponent
  componentId="my-component"
  loader={<MyopLoader />}  // Opt-in to default Myop loader
  fadeDuration={300}
/>
```

### Custom Loading State

```tsx
<MyopComponent
  componentId="my-component"
  loader={
    <div className="custom-loader">
      <Spinner />
      <p>Loading component...</p>
    </div>
  }
  fadeDuration={300}
/>
```

### Custom Error Fallback

```tsx
import { MyopComponent, MyopFallback } from "@myop/react";

<MyopComponent
  componentId="my-component"
  fallback={
    <div className="error-state">
      <p>Failed to load component</p>
      <button onClick={() => window.location.reload()}>Retry</button>
    </div>
  }
/>

// Or use the default Myop fallback explicitly
<MyopComponent
  componentId="my-component"
  fallback={<MyopFallback />}
/>
```

## API Reference

### Exports

| Export | Description |
|--------|-------------|
| `MyopComponent` | Main component for embedding Myop components |
| `MyopLoader` | Default Myop-branded loading indicator (opt-in) |
| `MyopFallback` | Default Myop-branded error fallback |
| `preloadComponents` | Preload components for faster rendering |
| `isPreloaded` | Check if a component is cached |
| `enableLocalDev` | Enable local development mode |
| `setCloudRepositoryUrl` | Set custom server URL |
| `setCloudRepository` | Set custom CloudRepository instance |
| `getCloudRepository` | Get current CloudRepository instance |
| `setEnvironment` | Set default environment |
| `IComponentInstanceConfig` | TypeScript interface for component config |
| `IPropTypes` | TypeScript interface for component props |

## License

MIT