frame-bridge

Quick Start

Three packages — pick what you need. Start with the core, add React and DevTools when ready.

1. Vanilla JS / TypeScript

Install the core package. No runtime dependencies — only browser APIs.

npm install @mhanzelka/frame-bridge
parent.ts
import { createBridge } from "@mhanzelka/frame-bridge";

type Messages = { type: "ping" | "pong"; value: number };

const parent = createBridge<Messages>({
    channelName: "my-channel",
    role: "parent",
    enabled: ["broadcast-channel"],
});

await parent.open();

// Send a request and wait for the response
const reply = await parent.send({ type: "ping", value: 1 });
console.log(reply); // { type: "pong", value: 2 }
child.ts
import { createBridge } from "@mhanzelka/frame-bridge";

type Messages = { type: "ping" | "pong"; value: number };

const child = createBridge<Messages>({
    channelName: "my-channel",
    role: "child",
    enabled: ["broadcast-channel"],
});

await child.open();

child.onMessage(async (msg) => {
    if (msg.type === "ping")
        return { type: "pong", value: msg.value + 1 };
});
Both sides must use the same channelName. The role determines who initiates the handshake for MessageChannel transport.

2. React integration

Wrap your tree with BridgeProvider. Access the bridge anywhere via hooks. Peer deps: React 19+.

npm install @mhanzelka/react-frame-bridge @mhanzelka/frame-bridge
import { BridgeProvider, useBridge, useBridgeState } from "@mhanzelka/react-frame-bridge";

type Messages = { type: "ping" | "pong"; value: number };

function App() {
    return (
        <BridgeProvider<Messages>
            open={true}
            channelName="my-channel"
            role="parent"
            enabledTransports={["broadcast-channel"]}
        >
            <Controls />
        </BridgeProvider>
    );
}

function Controls() {
    const bridge = useBridge<Messages>();
    const state = useBridgeState();

    const handlePing = async () => {
        const reply = await bridge.send({ type: "ping", value: 1 });
        console.log(reply); // { type: "pong", value: 2 }
    };

    return (
        <div>
            <p>Status: {state.state}</p>
            <button onClick={handlePing} disabled={state.state !== "open"}>
                Send ping
            </button>
        </div>
    );
}

3. DevTools (optional)

Add a floating debug panel to your React app. Shows live messages, connection state, and request/response pairs.

npm install @mhanzelka/react-frame-bridge-devtools
import { BridgeConsoleDevTool } from "@mhanzelka/react-frame-bridge-devtools";
import "@mhanzelka/react-frame-bridge-devtools/styles.css";

function App() {
    return (
        <>
            {/* your app */}
            {process.env.NODE_ENV === "development" && (
                <BridgeConsoleDevTool buttonPosition="bottom-right" />
            )}
        </>
    );
}