Iframes
<iframe> ("inline frame") embeds another HTML document inside the current page, as its own independent browsing context with its own DOM, scripts, and history. It's the tool you reach for whenever you need to show content from a different origin or a separate document—maps, videos, payment widgets, embedded dashboards—without merging it into your own page.Basic Syntax
basic-iframe.html
<iframe src="https://example.com/widget" width="600" height="400" title="Example widget" ></iframe>
Attribute | Purpose |
|---|---|
src | URL of the document to embed |
title | Accessible name announced by screen readers—required in practice |
width / height | Rendered dimensions in pixels |
loading | "lazy" to defer off-screen iframes until needed |
allow | Grants specific permissions (camera, fullscreen, etc.) |
sandbox | Restricts what the embedded document can do |
title attribute. Without one, users hear only "iframe," with no idea what's embedded. A short, descriptive title like "Store location map" is required for accessible embeds.Common Use Cases
Embedding a map from a mapping provider.
Embedding a video player (YouTube, Vimeo, and similar services ship iframe embed codes).
Embedding third-party widgets: chat, comments, payment forms, social media posts.
Loading a self-contained “micro app” or dashboard from another origin.
Isolating untrusted or user-generated HTML from the rest of the page.
Example: Embedding a Video
video-embed.html
<iframe width="560" height="315" src="https://www.youtube.com/embed/dQw4w9WgXcQ" title="Product demo video" loading="lazy" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen ></iframe>
allow attribute: many embed providers require specific permissions (like autoplay or fullscreen) to be explicitly granted, since the iframe's content runs in an isolated context that doesn't automatically inherit permissions from the host page.Sizing an Iframe Responsively
width/height attributes don't adapt to different screen sizes. A common pattern wraps the iframe in a container that maintains an aspect ratio using CSS.responsive-iframe.html
<div style="aspect-ratio: 16 / 9; width: 100%;">
<iframe
src="https://example.com/player"
title="Responsive video player"
style="width: 100%; height: 100%; border: 0;"
></iframe>
</div>border: 0 (or style it deliberately) so the embed doesn't look accidental.<iframe> and </iframe> only renders in very old browsers that don't support iframes at all. Modern browsers always render the frame, so don't rely on that fallback for anything meaningful—use it only as a last-resort message.Embedding a Map
<iframe> snippet to paste directly into your page. These embeds handle their own panning, zooming, and markers entirely inside the frame.map-embed.html
<iframe src="https://maps.example.com/embed?pb=location-data" title="Map showing our store location in downtown Berlin" width="600" height="450" style="border: 0;" loading="lazy" referrerpolicy="no-referrer-when-downgrade" ></iframe>
referrerpolicy attribute above—some embed providers request a specific referrer policy so their analytics or quota systems work correctly. Copy the snippet exactly as the provider gives it unless you have a specific reason to change it.Same-Origin vs Cross-Origin Iframes
iframe.contentDocument). An iframe loading a different origin is subject to the browser's same-origin policy: your page's script cannot read or modify its contents at all, by design.Scenario | Can the parent page script the iframe? |
|---|---|
Same origin (e.g. both on example.com) | Yes — full DOM access via contentDocument/contentWindow |
Cross origin (e.g. parent on example.com, iframe on cdn.other.com) | No — blocked by the same-origin policy, except via postMessage |
window.postMessage() API, which lets two windows exchange messages safely without bypassing the origin boundary.post-message.html
<!-- Inside the iframe's own document -->
<script>
window.parent.postMessage({ type: 'resize', height: document.body.scrollHeight }, 'https://host-site.example.com');
</script>
<!-- On the parent page -->
<script>
window.addEventListener('message', (event) => {
if (event.origin !== 'https://widget-provider.example.com') return;
if (event.data.type === 'resize') {
document.getElementById('widget-frame').style.height = event.data.height + 'px';
}
});
</script>event.origin, any page anywhere could send your listener a crafted message. Treat unvalidated postMessage listeners as a security hole.Iframe vs Fetching HTML Yourself
It can be tempting to fetch another page's HTML and inject it directly into your DOM instead of using an iframe. Resist that urge for third-party content: an iframe keeps the embedded document's scripts, styles, and cookies fully isolated, while injecting raw HTML merges everything into your own page—including any scripts, which can break your page or introduce security issues.
Approach | Isolation | When appropriate |
|---|---|---|
<iframe src="..."> | Full — separate document, DOM, scripts, styles | Embedding third-party or untrusted content |
fetch() + innerHTML | None — merges into your own DOM and script context | Only for HTML fragments you fully trust and control |
An iframe embeds an entirely separate document with its own DOM and scripts.
Always include a descriptive title attribute for accessibility.
Use loading="lazy" for iframes that are off-screen on page load.
Grant only the permissions a third-party embed actually needs via the allow attribute.
See the security lesson for sandboxing and clickjacking protections when embedding untrusted content.