UNPKG

react-iframe

Version:

A zero-dependency, typed, ref-forwarding iframe component for React 18+

140 lines (100 loc) • 7.16 kB
# react-iframe Zero-dependency typed React wrapper around [`<iframe>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe). ```bash npm install react-iframe ``` ```tsx import Iframe from "react-iframe" ;<Iframe url="https://media.w3.org/2010/05/sintel/trailer.mp4" width="100%" height="320" allow="autoplay; fullscreen" allowFullScreen title="Sintel trailer" /> ``` You do not need this package to render an iframe. Use it when you want TypeScript types, a `ref` to the real `HTMLIFrameElement`, `url` / array `sandbox` / `allowFullScreen` conveniences, or the small `postMessage` helpers. Requires **React 18 or 19**. ## Props The component accepts every native iframe attribute (`src`, `srcDoc`, `allow`, `loading`, `referrerPolicy`, `fetchPriority`, `credentialless`, `title`, event handlers, aria attributes, …) plus: | Prop | Type | Notes | | ----------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------- | | `url` | `string` | Alias for `src`. Provide **one of** `url`, `src`, or `srcDoc`. `srcDoc` wins, then `src`, then `url`. | | `srcDoc` | `string` | Inline HTML document. Omits `src` when set. | | `sandbox` | `string` \| `string[]` | Arrays are joined with spaces. Strings are left intact. | | `allowFullScreen` | `boolean` | Sets the boolean attribute **and** prepends `fullscreen` to `allow` (semicolon-separated, no duplicates). | | `styles` | `CSSProperties` | Merged into `style`. Precedence: `style` > `styles` > `display` / `position` / `overflow` / `frameBorder`. | | `display` / `position` / `overflow` | CSS values | Style shortcuts. **No defaults** — omit them to keep the browser UA stylesheet. | | `frameBorder` | `number` \| `string` | Maps to `style.border` unless `style`/`styles` already set `border`. Prefer `style={{ border: 0 }}`. | Deprecated 1.x aliases still work: `referrerpolicy` → `referrerPolicy`, `importance` → `fetchPriority`, `allowpaymentrequest` → `allow="payment"`. At least one of `url`, `src`, or `srcDoc` is required by the type definition. ## Refs and postMessage ```tsx import { useRef } from "react" import Iframe, { postToIframe, useIframeMessage } from "react-iframe" function Widget() { const ref = useRef<HTMLIFrameElement>(null) useIframeMessage( (event) => { if (event.data?.type === "ready") { postToIframe(ref.current, { type: "init" }, event.origin) } }, { origin: "https://widget.example", source: ref }, ) return ( <Iframe ref={ref} url="https://widget.example/embed" title="Widget" width="100%" height="400" /> ) } ``` `ref.current` is the DOM iframe. Same-origin frames expose `contentDocument` / `contentWindow`. Cross-origin frames do not — use `postMessage`. `onError` is attached as a native listener and receives a DOM `Event`, not a React synthetic event. React itself only wires iframe `load`, not `error`. `useIframeMessage` can filter by `origin` and by `source` (the iframe node, a ref, or a `Window`). Prefer `source` when more than one frame can share an origin. A `srcDoc` document has origin `"null"` (the string); pass `{ origin: "null" }` or filter with `source`. `postToIframe` requires a `targetOrigin` — the child origin, or `"*"` for `srcDoc` (the browser rejects `"null"` as a target origin). ## Permissions policy (`allow`) Tokens are **semicolon-separated**, optionally with an origin: ```tsx <Iframe url={pageUrl} allow="microphone *; camera *; midi *; clipboard-write; clipboard-read; fullscreen" allowFullScreen /> ``` A space-separated list (`allow="microphone camera"`) is invalid and browsers will log “Unrecognized origin”. ## FAQ **Can I read a video’s duration, hide scrollbars, or detect scroll-to-end inside the frame?** Only if the framed document is **same-origin**, via `ref.current.contentDocument`. Cross-origin access is blocked by the browser. Have the child page `postMessage` the data you need. **Why is `sessionStorage` / cookies denied?** Sandboxing, third-party cookie blocking, or [`credentialless`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy#credentialless_iframes) isolation. Not a library bug. **Can I set `Authorization` headers on the iframe request?** No. `<iframe src>` cannot attach custom HTTP headers. Use a same-origin proxy, cookies, or a query token the server accepts. **Safari never fires `onLoad` for my payment frame.** That is a UA quirk. Have the child document `postMessage` when it is ready, and listen with `useIframeMessage`. **Why is `event.origin` `"null"` for `srcDoc`?** A `srcDoc` document is an opaque origin. `MessageEvent.origin` is the string `"null"`. Pass `{ origin: "null" }` to `useIframeMessage`. When posting back, use `postToIframe(iframe, message, "*")` — browsers reject `"null"` as `targetOrigin`. Filtering with `source` does not depend on that string. **PDF on iPad only shows the first page.** iOS Safari’s PDF-in-iframe behavior. Use [PDF.js](https://mozilla.github.io/pdf.js/) or `<object>`/`<embed>` as a workaround. **YouTube (or another embed) is blank on mobile.** Pass a complete `allow` list and `allowFullScreen`. Autoplay is still subject to the browser’s media policies. **How do I render a local HTML file?** Point `src` at a URL the app can serve (`/banner.html`), or pass the markup as `srcDoc`. A relative path that your bundler does not emit will 404 and may look like “it rendered my app instead.” **Does this bypass `X-Frame-Options` / CSP `frame-ancestors`?** No. If the target site forbids embedding, no wrapper can override that. ## Migrating from 1.8.x Most call sites keep working (`url`, `styles`, `sandbox` arrays, layout shortcuts). Breaking changes in **2.0**: - Peer dependency is React **18+**. 1.8.5 remains on npm for React 16/17. - `sandbox="allow-scripts"` is no longer exploded into `"a l l o w - s c r i p t s"`. - `allowFullScreen` is a real boolean. It is **not** always set to the string `"allowFullScreen"`. Combined with `allow`, tokens are joined with `"; "`. - No default `display: initial` / `display: block`. - `ref` is forwarded to the `<iframe>` (this was broken since 1.7). - `onLoad` receives a React synthetic event. `onError` receives a native DOM `Event` (React does not synthesize iframe `error`). - Invalid DOM props (`target`, `key` as an HTML attribute) are no longer written onto the node. - The package is dual ESM/CJS with an `exports` map. Types ship from `dist/`. ## Development ```bash npm install npm test npm run build npm run demo ```