Skip to content
sandbox logoSandboxUI Primitives
Isolated iframe runtime with a typed state bridge and explicit message trust boundary for safe execution of untrusted HTML — component previews, playgrounds, plugin sandboxes, and more.
Version
v3.0.0
Size
3.3 KB gzip
Dependencies
Zero dependencies
Browser
createSandboxSandboxConfigurationErrorSandboxErrorSandboxTimeoutErrorSandboxHandle View all 8 exports

Why Sandbox?

Running untrusted HTML in the main window is unsafe — arbitrary code can access the DOM, cookies, and user data. Sandbox creates an isolated <iframe sandbox="allow-scripts"> that receives content over a typed state bridge and explicit message trust boundary. The sandbox cannot reach the host page.

ts
// Before
container.innerHTML = untrustedHtml;

// After
const sandbox = createSandbox(container);
await sandbox.render(untrustedHtml);

Common use cases:

  • Component previews — render isolated HTML/CSS examples in documentation or design tools
  • Code playgrounds — execute user-provided code with full error forwarding and state injection
  • Plugin sandboxes — host third-party or user-authored plugin UI without granting host access
  • User-generated content — display untrusted HTML (emails, form output, external widgets) safely
  • Widget embedding — wrap third-party widgets with strict CSP and bidirectional messaging
  • AI-generated UI — render LLM-produced HTML components with guaranteed isolation
FeatureRaw <iframe>Sandbox
Bundle size0 B (built-in)3.3 KB
Zero dependencies
Content-Security-PolicyManualAuto-generated, strict by default
Managed message protocolTyped host state; untrusted inbound details
Error forwardingonerror + unhandledrejection → host
Dispose / usingManual remove()dispose() + [Symbol.dispose]

Use Sandbox when you need to render untrusted or user-provided HTML in the browser with iframe isolation, CSP enforcement, and explicit host/sandbox messaging.

Consider a raw <iframe> when you only need to embed a known third-party URL — Sandbox is for programmatic srcdoc content, not URL-based embedding.

Installation

sh
pnpm add @vielzeug/sandbox
sh
npm install @vielzeug/sandbox
sh
yarn add @vielzeug/sandbox

Quick Start

ts
import { createSandbox } from '@vielzeug/sandbox';

const container = document.getElementById('preview')!;
const sandbox = createSandbox<{ theme: 'dark' | 'light' }>(container);

sandbox.onMessage((message) => {
  if (message.type === 'custom') console.log(message.event, message.detail);
  if (message.type === 'error') console.error(message.message);
  if (message.type === 'resize') console.log('height:', message.height);
});

try {
  await sandbox.render('<ore-button variant="primary">Click me</ore-button>');
  sandbox.setState({ theme: 'dark' });
} catch (error) {
  console.error('Sandbox render failed', error);
} finally {
  sandbox.dispose();
}

Features

  • createSandbox<State>() — Creates an isolated <iframe sandbox="allow-scripts"> with typed outbound state
  • render(html) — Creates or replaces the document and resolves when its bridge reports ready
  • setState(update) — Pushes one or more typed state values in one message
  • replaceBody(html) — Updates streamed body content without resetting head scripts and styles
  • updateStyle(id, css) — Patches a named style without replacing the document
  • SandboxMessage — Keeps sandbox-controlled custom details typed as unknown on the host
  • SandboxBridge<State, Events> — Types authored sandbox-side state subscriptions and event emission
  • readyTimeout — Rejects blocked document initialization with SandboxTimeoutError
  • Strict CSP — Uses default-src 'none' and blocks network requests by default
  • Error forwarding — Installs before user scripts and forwards uncaught errors and rejections
  • Stale-message protection — Rejects messages from superseded render generations
  • Disposable — Supports dispose(), disposalSignal, and [Symbol.dispose]

Documentation

See Also

  • Codex — MCP server with generate-sandbox-document and get-state-bridge-spec tools; generates document templates for use with Sandbox
  • Refine — Web component library; renders correctly inside the sandbox via <script> injection and allowedScriptOrigins