An <iframe> (inline frame) embeds a second, complete document inside the page, with its own window, document, history and JavaScript globals. Maps, video players, payment forms, ads, code playgrounds and chat widgets are all iframes. If the embedded document comes from the same origin, the parent can reach into it through iframe.contentDocument; if not, the same-origin policy walls it off, and the two sides can talk only through window.postMessage() (see The Window Object for the Window object).
| Attribute | Purpose |
|---|---|
| src / srcdoc | URL to load, or inline HTML that overrides src |
| title | Accessible name that screen readers announce; always set it |
| width, height | Size in CSS pixels (default 300 x 150); CSS works too |
| name | Target name for <a target> and <form target> |
| loading="lazy" | Defers loading until the frame nears the viewport |
| allow, allowfullscreen | Permissions policy for camera, geolocation, fullscreen (Permissions Policy) |
| sandbox | Applies restrictions, lifted one token at a time (Sandboxing and Trusted Types) |
| referrerpolicy | How much of the parent URL is sent as Referer |
srcdoc is handy for previews, sandboxed user content and demos, because the document needs no separate file. A srcdoc frame shares the parent's origin unless it is sandboxed, so the parent can measure it and grow the frame to fit its content, a trick that cross-origin frames cannot use.
<style>
body { font: 15px system-ui; margin: 12px; }
iframe { display: block; width: 100%; margin: 8px 0; border: 2px solid #1565c0; }
</style>
<iframe title="Release note" srcdoc="<body style='font:15px system-ui; margin:0; padding:8px'>
<b>Version 2.4</b> adds offline mode and a dark theme.
<p id=p>Scripts blocked</p>
<script>p.textContent = 'Frame title: ' + frameElement.title</script>"
onload="this.style.height = this.contentDocument.body.scrollHeight + 'px'"></iframe>
<iframe title="Untrusted widget" sandbox height="40"
srcdoc="<body style='font:15px system-ui; margin:0; padding:8px'>
<b id=p>Scripts blocked</b>
<script>p.textContent = 'Frame title: ' + frameElement.title</script>"></iframe>
The first frame's script runs and reads the title of its own <iframe> element through frameElement, and the parent's onload handler resizes the frame so no scroll bar appears. The second frame has an empty sandbox attribute, which applies every restriction: no scripts, no forms, no popups, no top-level navigation and an opaque origin.
Common embeds
A hidden same-origin frame can print a document without displaying it, and a YouTube 9 player is a cross-origin frame whose allow list grants the features the player needs:
<iframe id="receipt" src="/orders/1042/receipt" hidden></iframe>
<button onclick="receipt.contentWindow.print()">Print receipt</button>
<iframe width="560" height="315" loading="lazy" title="Product tour video"
src="https://www.youtube-nocookie.com/embed/VIDEO_ID"
allow="autoplay; encrypted-media; picture-in-picture" allowfullscreen></iframe>The youtube-nocookie.com domain is YouTube's privacy-enhanced mode, in which views of the embed do not influence the viewer's YouTube recommendations or ads. Each player still downloads the full player code even if nobody presses play, so pages with many videos often use lite-youtube-embed 6,349 (https://github.com/paulirish/lite-youtube-embed 6,349 ) (Apache-2.0, npm 2,036 install lite-youtube-embed), a custom element that shows a thumbnail and swaps in the real iframe only on click. For cross-origin auto-sizing, iframe-resizer 6,931 (https://github.com/davidjbradshaw/iframe-resizer 6,931 ) runs a script on both sides that reports the content height through postMessage(); version 4 was MIT-licensed, but version 5 is GPL-3.0 or a paid commercial license, so a closed-source site either buys one or writes the dozen lines of ResizeObserver plus postMessage() itself.
Pitfalls: many sites forbid framing with the X-Frame-Options header or the CSP frame-ancestors directive, and the frame then shows an error page (Content Security Policy). The attributes frameborder, scrolling, marginwidth, marginheight and allowtransparency from old embed codes, including YouTube's own, are obsolete; use CSS border and overflow instead. Finally, never combine allow-scripts with allow-same-origin for a same-origin document: the specification warns that the framed page can simply remove its own sandbox and reload.