Skip to content

API Reference

The virtual-frame package exposes a low-level class (VirtualFrame), a custom element (<virtual-frame>), and a cross-origin bridge entry point. Most applications use a framework wrapper (see the framework guides) and never touch these APIs directly — reach for them when you need fine-grained control over projection lifetime, roots, or transports.

VirtualFrame class

js
import { VirtualFrame } from "virtual-frame";

The projection engine. Given a source <iframe> and a host element, it mirrors the iframe's live DOM into the host — with mutation tracking, event re-dispatch, CSS rewriting, and optional Shadow DOM isolation.

Constructor

ts
new VirtualFrame(
  iframe: HTMLIFrameElement,
  host: HTMLElement,
  options?: VirtualFrameOptions,
)

Projection starts immediately; the constructor calls init() internally. Subscribe to the iframe's load event or await navigation separately if you need a "ready" signal.

ParameterTypeDescription
iframeHTMLIFrameElementSource iframe whose document will be projected
hostHTMLElementContainer element that receives the projected DOM
optionsVirtualFrameOptionsSee Options. Optional.

Options

The VirtualFrameOptions type:

ts
interface VirtualFrameOptions {
  isolate?: "open" | "closed";
  selector?: string;
  streamingFps?: number | Record<string, number>;
}
OptionTypeDefaultDescription
isolate"open" | "closed"undefinedAttach a Shadow DOM of the given mode to the host for CSS isolation. Omit to render into the host's light DOM. See Shadow DOM.
selectorstringundefinedCSS selector to project only a matching subtree of the iframe document. See Selector Projection.
streamingFpsnumber | Record<string, number>undefinedFrames-per-second for canvas/video streams. undefined means smooth per-frame (rAF) rendering same-origin; cross-origin falls back to ~5 FPS (set an explicit number for higher). A { selector: fps } map allows per-element rates. See Streaming FPS.

Custom element only

The <virtual-frame> element also accepts a proxy attribute (same-origin fetch/XHR rewrite prefix). This is not part of VirtualFrameOptions — it's applied to the generated env shim before the iframe loads. See <virtual-frame> below and Cross-Origin.

Properties

Read-only after construction.

PropertyTypeDescription
iframeHTMLIFrameElementThe source iframe passed to the constructor.
hostHTMLElementThe host element receiving projected content.
isolate"open" | "closed" | undefinedShadow DOM mode in use.
selectorstring | nullCSS selector, normalized to null when omitted.
streamingFpsnumber | Record<string, number> | undefinedThe FPS configuration in effect.
shadowRootShadowRoot | nullOpen shadow root, when isolate: "open". For closed mode use getShadowRoot().
isInitializedbooleantrue after init() has completed at least once.

Methods

destroy()

ts
destroy(): void

Stop projecting and release resources: detach the MutationObserver, remove event/message listeners, stop canvas/video capture streams, delete injected FontFace entries, and clear the host subtree. Safe to call multiple times. After destroy() the instance can be revived with refresh().

refresh()

ts
refresh(): void

Equivalent to destroy(); init(). Use when the source iframe has changed in a way the mutation observer can't see (e.g., you replaced the iframe's src programmatically and want a clean re-projection without recreating the VirtualFrame instance).

getShadowRoot()

ts
getShadowRoot(): ShadowRoot | null

Returns the shadow root attached to the host, regardless of "open" or "closed" mode. Use this when isolate: "closed" prevents access via host.shadowRoot. Returns null if isolate was not set.

init() internal

Called automatically by the constructor and by refresh(). You typically don't need to invoke this directly; it is documented for completeness.


<virtual-frame> custom element

js
import "virtual-frame/element";

Declarative wrapper around VirtualFrame. Each element manages its own hidden <iframe> (shared between sibling elements pointing at the same src to avoid duplicate loads) and projects into its own subtree.

Attributes

HTML attributes use kebab-case and always stringify. The element maps them to camelCase options at setup time.

AttributeMaps toDescription
srcURL of the remote document, or #id to reference an existing <iframe> / element in-page.
isolateisolate"open" or "closed".
selectorselectorCSS selector to project a subtree.
streaming-fpsstreamingFpsEither a number (e.g. streaming-fps="30") or a JSON object (e.g. streaming-fps='{"canvas":30,"video":60}').
proxy— (env shim)Same-origin proxy prefix for fetch/XHR rewriting. See Cross-Origin.

Any attribute change on a connected element triggers a teardown + re-setup on the next microtask. To swap the source without restarting projection, prefer calling refresh() on the underlying VirtualFrame.

Methods

refresh()

ts
element.refresh(): void

Equivalent to the VirtualFrame method of the same name — force a full re-projection.


Bridge entry point

js
// Served from the remote origin before any framework code
import "virtual-frame/bridge";

The bridge is a small script that runs inside the projected document when it lives on a different origin than the host. It serialises DOM, CSS, events, and input back to the host via postMessage. See Cross-Origin for the end-to-end flow and the message protocol.


Types

VirtualFrameOptions

ts
export interface VirtualFrameOptions {
  isolate?: "open" | "closed";
  selector?: string;
  streamingFps?: number | Record<string, number>;
}

See Options.

EnvShimOptions

ts
export interface EnvShimOptions {
  /**
   * Same-origin proxy prefix. When set, the fetch/XHR shim rewrites
   * host-origin requests to `location.origin + proxyBase + pathname`,
   * keeping traffic same-origin and avoiding CORS.
   *
   * The host server must proxy `proxyBase/:path*` → `remoteOrigin/:path*`.
   */
  proxyBase?: string;
}

Consumed by the internal _buildEnvShim() helper that composes the <script> injected into the projected iframe before any framework code runs. Framework integrations and the custom element expose this as proxy / proxyBase.


SSR entry point

js
import {} from /* … */ "virtual-frame/ssr";

Server-side helpers used by the Next.js, Nuxt, SvelteKit, TanStack Start, and other SSR integrations to seed projection payloads at render time. Most users consume these transitively through a framework wrapper. See the SSR guide for the primitives (fetchVirtualFrame, renderVirtualFrame) and the Next.js guide for a framework-integrated walkthrough.


Framework packages

Each framework package wraps the core engine with idiomatic bindings (components, hooks, signals, stores). See the guide for the package you use:

PackageGuide
@virtual-frame/reactReact
@virtual-frame/nextNext.js
@virtual-frame/react-routerReact Router
@virtual-frame/tanstack-startTanStack Start
@virtual-frame/react-server@lazarv/react-server
@virtual-frame/vueVue
@virtual-frame/nuxtNuxt
@virtual-frame/svelteSvelte
@virtual-frame/sveltekitSvelteKit
@virtual-frame/solidSolid
@virtual-frame/solid-startSolidStart
@virtual-frame/angularAngular
@virtual-frame/analogAnalog
@virtual-frame/storeShared Store