Skip to content

Getting started

pnpm add react-iframe-kit

React 18 or 19 is a peer dependency. The package has these entry points:

Import Use it in Needs React Gives you
react-iframe-kit the page that owns the <iframe> yes <Frame>, useFrame, useIframe, useIframeResize, useIframeRPC, useIframeEvent, useIframeTitle, useIframeInert, useIframeLoad
react-iframe-kit/child the page inside the iframe no connectToParent
react-iframe-kit/child/lite the page inside the iframe, when it needs no RPC no connectToParent for resize, title and inert only: 4 kB instead of 6 kB
react-iframe-kit/child/react the page inside the iframe yes useParent, useParentEvent
react-iframe-kit/host the page that owns the <iframe>, when it isn’t a React app no connectToIframe: resize, RPC, events, title and inert, see Embedding a widget
react-iframe-kit/validate either page no validateArgs, validatePayload: runtime checks with any Standard Schema library
react-iframe-kit/testing your tests no mockChild, mockParent
react-iframe-kit/devtools either page, in development no onProtocolMessage, connectReduxDevTools: the protocol traffic in Redux DevTools

A page without a bundler can load a child entry from a CDN as a script; it defines a global ReactIframeKit. For a page that only needs to be sized, the lite build is enough. The snippet is pinned to a version and carries its integrity hash, so the file can’t change under you; to upgrade, copy the snippet again from here.

<script src="https://cdn.jsdelivr.net/npm/react-iframe-kit@0.4.1/dist/child-lite.global.js" integrity="sha384-G/R0WtqBlBdgSWiF8bwxPPWfb0/wos/S8kmLhGCprzDWgGEjVeLygLtQEwSBckg8" crossorigin="anonymous"></script>
<script>
ReactIframeKit.connectToParent({ allowedOrigins: ['https://app.example.com'], autoResize: true });
</script>

With methods or events, load dist/child.global.js instead.

When you own the content, render it straight into a same-origin iframe:

import { Frame } from 'react-iframe-kit';
<Frame title="Preview" resize copyStyles>
<Invoice data={invoice} />
</Frame>;

More in Portal rendering.

The child page reports its size, and the parent applies it:

// parent
import { useIframeResize } from 'react-iframe-kit';
const ref = useRef<HTMLIFrameElement>(null);
useIframeResize(ref, { maxHeight: 2000 });
return <iframe ref={ref} title="Widget" src="https://widget.example.com/" />;
// child (https://widget.example.com)
import { connectToParent } from 'react-iframe-kit/child';
connectToParent({ allowedOrigins: ['https://app.example.com'], autoResize: true });

More in Auto-resize.

shared/contract.ts
import type { Side } from 'react-iframe-kit';
export type ParentSide = Side<{ methods: { getUser(): { name: string } } }>;
export type ChildSide = Side<{
methods: { setTheme(theme: 'light' | 'dark'): void };
events: { submitted: { id: string } };
}>;
// parent
const { remote, status } = useIframeRPC<ChildSide, ParentSide>(ref, {
methods: { getUser: () => currentUser },
});
await remote.setTheme('dark');
// child
const parent = connectToParent<ParentSide, ChildSide>({
allowedOrigins: ['https://app.example.com'],
methods: { setTheme },
});
const user = await parent.remote.getUser();

More in RPC and events. Resize and RPC on the same iframe share one connection and one handshake.