iframe-embed-contracts

Installation
SKILL.md

Iframe embed contracts

An iframe integration has two applications and one browser boundary. Treat the parent and guest as separate deploys with an explicit protocol: who may embed whom, which capabilities are delegated, how readiness and messages are authenticated, how size and navigation are synchronized, and what happens when storage or the frame disappears.

Checklist

  1. Classify both sides before editing. Record whether you own the parent, guest, or both; the exact origins in every environment; whether the frame is same-origin, cross-origin, srcdoc, or sandboxed to an opaque origin; and whether the guest must support more than one parent. Do not infer a cross-origin frame's health from DOM access that the same-origin policy intentionally blocks.
  2. Inspect the delivered frame policy, not only JSX. Capture the final <iframe> attributes and the guest response headers. The parent controls where frames may load (frame-src), while the guest controls who may embed it (frame-ancestors, with X-Frame-Options only as a legacy fallback). frame-ancestors is HTTP-header-only and does not fall back to default-src; a meta CSP cannot prove the production embedding contract.
  3. Make readiness a replayable handshake. load is not success: browsers fire it even when the frame's resource failed, and a guest can post READY before the parent listener attaches. Register the listener before setting src, let the guest emit {type, version, instanceId} READY, let the parent answer with bounded init/config, and keep a timeout/diagnostic state instead of a permanent spinner. If either side may reload or navigate, make READY and init idempotent.
  4. Authenticate every message in both directions. Send with an exact targetOrigin; on receive, verify event.origin, event.source === iframe.contentWindow (or the expected parent window), message type/version, and payload schema before acting. An origin allowlist alone is insufficient when several frames share it. A sandboxed srcdoc/opaque guest reports origin null; if that architecture is unavoidable, bind the channel to the exact source plus an unguessable per-instance nonce or transferred MessagePort, and expose minimal capabilities rather than accepting every null sender.
  5. Grant the minimum sandbox and feature capabilities. Start from a restricted sandbox and add only required tokens. For same-origin content, allow-scripts plus allow-same-origin lets the guest remove its sandbox, so untrusted active content belongs on a separate origin. Browser features need both layers: the response Permissions-Policy sets the outer ceiling and the iframe allow attribute may narrow/delegate within it. Test forms, popups, downloads, fullscreen, camera/microphone, clipboard, and top navigation only if the product actually needs them.
  6. Treat dynamic sizing as a bounded protocol. A cross-origin parent cannot read guest layout. Reserve an initial box to avoid CLS, observe the guest's actual content box with ResizeObserver, coalesce messages to one animation frame, include an instance/sequence id, and clamp the height in the parent to sane min/max values. Do not use the guest document's viewport-bounded scrollHeight as the only shrink signal: after the parent grows the iframe, that value can stay pinned to the larger viewport and create a parent resize -> guest measurement feedback loop. Test growth and shrink, fonts/images/async content, hidden-to-visible transitions, and mobile widths. Use a maintained resizer library when its protocol fits rather than copying a partial snippet.
  7. Design for partitioned storage and blocked third-party cookies. An embedded guest may not see the same cookies/storage it sees top-level. Prefer an explicit parent-to-guest session exchange with short-lived, audience-bound data over long-lived tokens in the URL. If unpartitioned cookie access is essential, the Storage Access API is permission- and user-activation-dependent; provide a top-level sign-in or recovery path and test denial.
  8. Make navigation and teardown observable. Remove message listeners, ResizeObservers, timers, and channels when the frame unmounts or the instance id changes. Revalidate origin/source after guest navigation. Expose guest error/timeout states to the parent, but do not treat the iframe load event as authoritative failure evidence.
  9. Preserve accessibility and performance contracts. Give every meaningful frame a concise title; reserve dimensions; lazy-load only below-the-fold, non-critical frames; and provide an equivalent link/fallback when the embedded surface is not the only way to complete a critical task.

Quick probes

Use matches as leads, then trace the parent and guest together:

Installs
1
GitHub Stars
1
First Seen
3 days ago
iframe-embed-contracts — voidmatcha/frontend-niche-skills