Embedded Content

Embed external content such as maps and videos using <iframe>, understand the security implications of embedding third-party code, use the sandbox attribute to restrict it, and build responsive iframe containers.

Sometimes the content you want on a page doesn't live in your HTML at all — a Google Map, a YouTube video, a payment widget, an embedded tweet. The <iframe> element lets you embed an entire separate web page inside a rectangular region of your own page. It's powerful, but because it's literally running someone else's webpage inside yours, it comes with real security considerations.

The <iframe> Element

<iframe> (inline frame) creates a nested browsing context — essentially a mini browser window embedded in your page, loading whatever URL you point it at via the src attribute. The embedded page runs independently: it has its own DOM, its own scripts, its own styles, isolated from the page that contains it.

Typical uses include embedding a Google Map, a YouTube or Vimeo video player, a third-party comment widget, a payment form provided by a payment processor, or a live chat widget.

Basic Attributes

src is the URL of the page to embed. width and height set the iframe's dimensions (same layout-shift reasoning as images and video applies here). title is important for accessibility — screen readers announce it so users understand what the embedded frame contains, since an untitled iframe is just announced as 'iframe' with no context.

allowfullscreen permits the embedded content (like a video player) to be expanded to fullscreen. loading="lazy" works on iframes too, deferring offscreen embeds just like it does for images.

Security: Why Embedding Third-Party Code Is Risky

An <iframe> can run arbitrary JavaScript, submit forms, open pop-ups, request permissions like camera or location access, and — depending on how it's configured — potentially interact with the page that embeds it. If you embed a page you don't fully control or trust, you are effectively giving that third party a window to run code alongside your own site.

This matters even for seemingly-safe embeds: a compromised ad network, a hijacked third-party widget, or a malicious link disguised as legitimate content can use an unrestricted iframe to launch phishing pop-ups, redirect users, or worse. The browser's same-origin policy provides some baseline isolation automatically, but the sandbox attribute lets you tighten that further, explicitly.

The sandbox Attribute

Adding sandbox to an <iframe> applies a strict set of restrictions to the embedded content by default: no script execution, no form submission, no pop-ups, no plugins, and the embedded content is treated as coming from a unique, isolated origin. An empty sandbox="" is the most locked-down setting possible.

You then re-enable only the specific capabilities the embed actually needs, as a space-separated list of tokens in the sandbox attribute's value — never by leaving sandbox off entirely just because restricting it broke something.

• allow-scripts — permits JavaScript to run inside the frame • allow-forms — permits form submission from inside the frame • allow-popups — permits the frame to open new windows/tabs • allow-same-origin — treats the frame as being from its actual origin rather than a unique isolated one (use cautiously — combined with allow-scripts this can undo some of sandbox's protection) • allow-top-navigation — permits the frame to navigate the entire top-level page, not just itself

Responsive Iframe Containers

An <iframe> given fixed width and height attributes doesn't naturally resize with the page the way text does — on a narrow phone screen, a 640-pixel-wide iframe just overflows or gets awkwardly squished. The modern fix is CSS aspect-ratio: wrap the iframe in a container (or apply it directly to the iframe) with a fixed aspect-ratio like 16 / 9 and a width of 100%, so the frame's width fills its parent and its height scales proportionally to maintain the correct ratio at any screen size.

This CSS technique replaces an older, clunkier method that used a padding-bottom percentage trick to fake aspect-ratio before the aspect-ratio CSS property existed.

A Sandboxed, Responsive Iframe

sandbox with an explicit token list grants only the permissions actually needed title is required for accessibility, describing what the embed contains sizing is handled in CSS via aspect-ratio, not fixed width/height attributes here

<div class="video-embed">
  <iframe
    src="https://example.com/player"
    title="Product demo video"
    sandbox="allow-scripts allow-same-origin"
    loading="lazy"
    allowfullscreen>
  </iframe>
</div>

Code Examples

A straightforward embed of a third-party map, with a descriptive title for screen readers and loading="lazy" since maps are often placed lower on a contact or about page.

This embed needs JavaScript to run (allow-scripts) and needs users to submit comment forms (allow-forms), but is explicitly denied pop-ups, top-level navigation, and plugin access — limiting what the third-party code could do if it were ever compromised.

sandbox="allow-scripts allow-forms" An empty sandbox="" locks the frame down completely — no scripts, no forms, no pop-ups, treated as an isolated origin. Appropriate for rendering content you don't trust at all, like a preview of user-submitted HTML.

The wrapping div locks in a 16:9 ratio using aspect-ratio while filling 100% of its available width. The iframe inside stretches to 100% width and height of that container, so the whole embed scales smoothly at any screen size without distortion.

<iframe
  src="https://maps.example.com/embed?location=engineering-campus"
  title="Map showing the engineering campus location"
  width="600" height="450"
  loading="lazy">
</iframe>
<iframe
  src="https://widget.example.com/comments"
  title="Comments widget"
  sandbox="allow-scripts allow-forms"
  width="600" height="400">
</iframe>
<iframe
  src="https://untrusted-preview.example.com/render"
  title="Untrusted content preview"
  sandbox="">
</iframe>
<style>
  .video-embed {
    width: 100%;
    max-width: 800px;
    aspect-ratio: 16 / 9;
  }
  .video-embed iframe {
    width: 100%;
    height: 100%;
    border: 0;
  }
</style>

<div class="video-embed">
  <iframe
    src="https://video.example.com/embed/12345"
    title="Conference talk recording"
    allowfullscreen>
  </iframe>
</div>

Embedded Content Isolation

The iframe's content is a fully separate document; sandbox restricts what that separate document is allowed to do.

Your Page (example.com)
+---------------------------------------+
|  <h1>My Site</h1>                     |
|  <p>Check out this video:</p>         |
|                                        |
|  +---- <iframe sandbox="..."> -----+  |
|  |  Separate page (video.com)      |  |
|  |  own DOM / own scripts / own    |  |
|  |  styles -- restricted by the    |  |
|  |  sandbox token list             |  |
|  +----------------------------------+ |
+---------------------------------------+

Important Rules

Always give an <iframe> a descriptive title attribute for accessibility.

Only embed content from sources you trust.

Use sandbox and grant the minimum set of allow- tokens the embed actually needs — never grant everything by default.

Size iframes responsively with CSS aspect-ratio rather than only fixed width/height attributes.

Use loading="lazy" for iframes that appear below the fold.

Where This Shows Up

Every embedded YouTube video, Google Map, Stripe payment form, or Twitter/X post you've ever seen on a website is an <iframe> under the hood, usually generated by an 'embed code' snippet the third-party service provides — often already including a title and reasonable defaults.

<iframe src="https://third-party-widget.example.com"></iframe>

<iframe src="https://third-party-widget.example.com" title="Support chat widget" sandbox="allow-scripts allow-same-origin" loading="lazy"></iframe>

No title hurts accessibility, and no sandbox attribute means the embedded page has unrestricted capabilities by default — including scripts, pop-ups, and top-level navigation.

<iframe src="video.html" sandbox="allow-scripts allow-same-origin allow-top-navigation allow-popups allow-forms"></iframe>

<iframe src="video.html" title="Embedded video" sandbox="allow-scripts allow-same-origin"></iframe>

Granting nearly every sandbox token defeats the purpose of sandboxing in the first place — only enable the specific permissions the embed genuinely requires.

[Multiple Choice] Why does the sandbox attribute exist on <iframe>, given that browsers already isolate embedded pages to some degree by default? A. It makes the iframe load faster by disabling image rendering inside it B. It lets the developer explicitly restrict a potentially untrusted embedded page's capabilities (like scripts, forms, and pop-ups) beyond the browser's default behavior, re-enabling only what's needed C. It is required syntax for any <iframe> to render at all D. It automatically resizes the iframe to fit its content responsively

B. It lets the developer explicitly restrict a potentially untrusted embedded page's capabilities (like scripts, forms, and pop-ups) beyond the browser's default behavior, re-enabling only what's needed — sandbox lets you lock an embedded page down to a minimal, explicitly-approved set of capabilities — since an iframe can otherwise run scripts, submit forms, and open pop-ups, which is risky when embedding content you don't fully control. It has nothing to do with load speed, is not required for rendering, and does not handle responsive sizing (that's CSS's job).

Embed a third-party 'live poll' widget that needs to run scripts and submit forms, but should not be allowed to open pop-ups or navigate the top-level page. Give it an accessible title and make it responsive using a 16:9 aspect-ratio container.

<style>.poll-embed { width: 100%; max-width: 600px; aspect-ratio: 16 / 9; }.poll-embed iframe { width: 100%; height: 100%; border: 0; } </style> <div class="poll-embed"> <iframe src="https://polls.example.com/embed/live-poll" title="Live audience poll" sandbox="allow-scripts allow-forms"> </iframe> </div> sandbox should list exactly allow-scripts and allow-forms — nothing more.