> ## Documentation Index
> Fetch the complete documentation index at: https://docs.morphllm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# VibeFrame

> Secure iframe rendering for AI-generated React components

# VibeFrame

VibeFrame renders AI-generated React components in a sandboxed iframe. It handles code compilation, data passing, auto-resizing, and error handling—all while maintaining strict security isolation.

## Basic Usage

```tsx theme={null}
import { VibeFrame } from 'genkit/react'

function Preview() {
  const code = `
    export default function Widget({ data }) {
      return (
        <div className="p-4 bg-blue-50 rounded-lg">
          <h2 className="text-xl font-bold">{data.title}</h2>
          <p className="text-gray-600">{data.description}</p>
        </div>
      )
    }
  `

  return (
    <VibeFrame
      code={code}
      data={{ title: 'Hello', description: 'World' }}
    />
  )
}
```

## Props

| Prop              | Type                                          | Default            | Description                                |
| ----------------- | --------------------------------------------- | ------------------ | ------------------------------------------ |
| `code`            | `string`                                      | -                  | React component code to render             |
| `id`              | `string`                                      | -                  | Component ID (for saved components)        |
| `data`            | `Record<string, unknown>`                     | `{}`               | Data passed to the component as props      |
| `rendererUrl`     | `string`                                      | `/api/vibe/render` | Base URL for the render endpoint           |
| `className`       | `string`                                      | -                  | CSS class for the container                |
| `minHeight`       | `number`                                      | `100`              | Minimum iframe height in pixels            |
| `maxHeight`       | `number`                                      | `600`              | Maximum iframe height in pixels            |
| `onRender`        | `() => void`                                  | -                  | Called when component renders successfully |
| `onError`         | `(error: string) => void`                     | -                  | Called when rendering fails                |
| `loadingFallback` | `ReactNode`                                   | -                  | Custom loading UI                          |
| `errorFallback`   | `ReactNode \| ((error: string) => ReactNode)` | -                  | Custom error UI                            |

## How It Works

### 1. Code Compilation

When you provide `code`, VibeFrame generates a data URL containing:

* React 18 (loaded from CDN)
* Babel standalone (for JSX compilation)
* Tailwind CSS (loaded from CDN)
* Your component code

```tsx theme={null}
// This code:
<VibeFrame code={myCode} />

// Becomes this data URL:
data:text/html;charset=utf-8,<!DOCTYPE html>...
```

### 2. PostMessage Bridge

The iframe and parent communicate via PostMessage:

```
Parent                          Iframe
  │                                │
  │  ───── VIBE_READY ──────────>  │  (iframe loaded)
  │                                │
  │  <──── VIBE_DATA ───────────   │  (parent sends data)
  │                                │
  │  ───── VIBE_RENDERED ───────>  │  (component rendered)
  │        { height: 240 }         │
  │                                │
  │  ───── VIBE_ERROR ──────────>  │  (if error occurs)
  │        { error: "..." }        │
```

### 3. Auto-Resize

The iframe automatically resizes based on content:

```tsx theme={null}
// Iframe sends its height after rendering
window.parent.postMessage({
  type: 'VIBE_RENDERED',
  height: document.body.scrollHeight
}, '*')
```

VibeFrame constrains this between `minHeight` and `maxHeight`.

## Security Model

### Sandbox Restrictions

```html theme={null}
<iframe sandbox="allow-scripts" />
```

This sandbox policy:

* ✅ Allows JavaScript execution
* ❌ Blocks same-origin access (can't read parent DOM)
* ❌ Blocks form submission
* ❌ Blocks popups and new windows
* ❌ Blocks top-level navigation
* ❌ Blocks plugins

### Code Validation

Before rendering, code is validated for dangerous patterns:

```tsx theme={null}
// These patterns are blocked:
eval()                // Dynamic execution
Function()            // Function constructor
new Function()        // Function constructor
import()              // Dynamic imports
require()             // CommonJS imports
process.              // Node.js globals
global.               // Node.js globals
window.               // Browser globals
document.             // DOM access
__proto__             // Prototype pollution
constructor[]         // Constructor access
```

## Rendering Modes

### Direct Code Rendering

Pass code directly for previews:

```tsx theme={null}
<VibeFrame
  code={generatedCode}
  data={previewData}
/>
```

### Saved Component Rendering

Pass an ID to render saved components:

```tsx theme={null}
<VibeFrame
  id="component-123"
  data={liveData}
  rendererUrl="/api/vibe/render"
/>
```

This fetches the component from your render endpoint.

## Custom Loading States

```tsx theme={null}
<VibeFrame
  code={code}
  data={data}
  loadingFallback={
    <div className="flex items-center gap-2">
      <Spinner />
      <span>Compiling component...</span>
    </div>
  }
  errorFallback={(error) => (
    <div className="text-red-500">
      <p>Failed to render: {error}</p>
      <button onClick={retry}>Try Again</button>
    </div>
  )}
/>
```

## Event Handling

```tsx theme={null}
function Preview() {
  const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading')
  const [error, setError] = useState<string | null>(null)

  return (
    <>
      <VibeFrame
        code={code}
        data={data}
        onRender={() => {
          setStatus('ready')
          analytics.track('component_rendered')
        }}
        onError={(err) => {
          setStatus('error')
          setError(err)
          analytics.track('component_error', { error: err })
        }}
      />

      {status === 'ready' && <Badge>Live</Badge>}
      {status === 'error' && <Alert>{error}</Alert>}
    </>
  )
}
```

## Data Updates

Data is automatically sent when it changes:

```tsx theme={null}
function LiveDashboard() {
  const [deals, setDeals] = useState([])

  useEffect(() => {
    const unsubscribe = subscribeToDeals(setDeals)
    return unsubscribe
  }, [])

  // VibeFrame re-renders when deals change
  return (
    <VibeFrame
      code={dashboardCode}
      data={{ deals }}
    />
  )
}
```

## API Endpoint Setup

For saved components, create a render endpoint:

```tsx theme={null}
// app/api/vibe/render/[id]/route.ts
import { NextRequest } from 'next/server'
import { vibeApi } from '@/lib/vibe'

export async function GET(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  const component = await vibeApi.load(params.id)

  if (!component) {
    return new Response('Not found', { status: 404 })
  }

  const html = generateRenderHtml(component.code)

  return new Response(html, {
    headers: { 'Content-Type': 'text/html' }
  })
}
```

## Best Practices

### 1. Always Set Max Height

Prevent malicious components from expanding infinitely:

```tsx theme={null}
<VibeFrame
  code={untrustedCode}
  maxHeight={600}
/>
```

### 2. Validate Data Before Passing

Don't pass sensitive data to generated components:

```tsx theme={null}
// ❌ Bad: Passing sensitive data
<VibeFrame data={{ user, apiKey, internalConfig }} />

// ✅ Good: Only pass display data
<VibeFrame data={{ userName: user.name, stats: publicStats }} />
```

### 3. Handle Errors Gracefully

Always provide error handling:

```tsx theme={null}
<VibeFrame
  code={code}
  onError={(error) => {
    toast.error('Component failed to render')
    logError(error)
  }}
  errorFallback={<ComponentErrorState />}
/>
```

### 4. Use Loading States

Show users something while compiling:

```tsx theme={null}
<VibeFrame
  code={code}
  loadingFallback={<Skeleton className="h-64" />}
/>
```
