Embedded Content
HTML 4.0
The iframe element creates a nested browsing context, allowing you to embed another HTML document within the current page. It’s commonly used for embedding third-party content like maps, videos, social media widgets, and external applications.
Interactive code playground requires JavaScript. Here's the code:
<!-- Simple iframe embedding an external page -->
<iframe
src="https://example.com"
width="600"
height="400"
title="Example website"
loading="lazy">
</iframe>
<!-- Secure iframe with sandbox -->
<iframe
src="https://external-app.com"
sandbox="allow-scripts allow-same-origin"
title="External application"
width="100%"
height="500">
</iframe>
< iframe src = " url " title = " description " ></ iframe >
The <iframe> element requires both opening and closing tags. Any content between the tags is displayed only if the browser doesn’t support iframes (rare in modern browsers).
Attribute Description Example srcURL of the embedded content src="https://example.com"titleAccessible description (required) title="Google Maps location"widthWidth in pixels or percentage width="600" or width="100%"heightHeight in pixels height="400"nameName for targeting name="main-frame"
Attribute Description Example sandboxEnables security restrictions sandbox="allow-scripts"allowPermissions Policy (formerly Feature Policy) allow="camera; microphone"referrerpolicyControls referrer information referrerpolicy="no-referrer"cspContent Security Policy for iframe csp="default-src 'self'"
Attribute Description Example loadingLazy loading behavior loading="lazy" or loading="eager"srcdocInline HTML content srcdoc="<p>Hello</p>"allowfullscreenEnable fullscreen API allowfullscreenallowpaymentrequestAllow Payment Request API allowpaymentrequest
Attribute Description Status frameborderBorder around iframe Deprecated - use CSS scrollingScrollbar behavior Deprecated - use CSS marginwidth, marginheightMargins Deprecated - use CSS alignAlignment Deprecated - use CSS
The sandbox attribute is your primary defense against malicious iframe content. It applies strict restrictions unless explicitly relaxed.
Interactive code playground requires JavaScript. Here's the code:
<!-- Most restrictive: sandbox with no values -->
<iframe
src="untrusted-content.html"
sandbox
title="Sandboxed content">
</iframe>
<!-- Allow scripts only -->
<iframe
src="trusted-app.html"
sandbox="allow-scripts"
title="App with scripts">
</iframe>
<!-- Multiple permissions -->
<iframe
src="interactive-widget.html"
sandbox="allow-scripts allow-forms allow-popups"
title="Interactive widget">
</iframe>
Value Description Use Case (empty) Maximum restrictions Untrusted content allow-scriptsAllow JavaScript execution Interactive content allow-same-originAllow same-origin access API calls to parent domain allow-formsAllow form submission Forms and inputs allow-popupsAllow opening new windows OAuth flows, external links allow-popups-to-escape-sandboxPopups escape sandbox Payment gateways allow-top-navigationAllow navigating parent Full-page navigation allow-downloadsAllow file downloads Document viewers allow-modalsAllow alert(), confirm() User confirmations allow-orientation-lockLock screen orientation Games, video players allow-pointer-lockCapture mouse pointer Games, 3D viewers allow-presentationAllow Presentation API Screen sharing allow-storage-access-by-user-activationStorage access after user interaction Embedded apps
<!-- Untrusted third-party content -->
src = " https://third-party.com/widget "
title = " Third-party widget " >
<!-- User-generated content -->
srcdoc = " < h1>User Content < /h1> "
<!-- NEVER DO THIS with untrusted content! -->
src = " https://untrusted-site.com "
sandbox = " allow-scripts allow-same-origin "
title = " Dangerous configuration " >
<!-- No sandbox at all! -->
src = " https://unknown-source.com "
The allow attribute controls which browser features the iframe can access.
Interactive code playground requires JavaScript. Here's the code:
<!-- Disable all features -->
<iframe
src="https://example.com"
allow=""
title="No features allowed">
</iframe>
<!-- Allow specific features -->
<iframe
src="https://video-player.com"
allow="autoplay; fullscreen; picture-in-picture"
title="Video player">
</iframe>
<!-- Geolocation for specific origin -->
<iframe
src="https://maps.example.com"
allow="geolocation https://maps.example.com"
title="Map with location">
</iframe>
Permission Description cameraAccess camera microphoneAccess microphone geolocationAccess location autoplayAutoplay media fullscreenEnter fullscreen mode paymentPayment Request API usb, bluetoothDevice access accelerometer, gyroscopeMotion sensors picture-in-picturePicture-in-picture mode
Implement CSP headers to control iframe sources:
<!-- In HTTP headers or meta tag -->
< meta http-equiv = " Content-Security-Policy "
content = " frame-src 'self' https://trusted-domain.com; frame-ancestors 'self'; " >
CSP Directives for Iframes:
frame-src: Controls which URLs can be embedded in iframes
frame-ancestors: Controls which sites can embed YOUR page in an iframe
child-src: Legacy fallback for frame-src
Interactive code playground requires JavaScript. Here's the code:
<!-- Page that allows being embedded -->
<meta http-equiv="Content-Security-Policy"
content="frame-ancestors 'self' https://trusted-embedder.com;">
<!-- Page that restricts iframe sources -->
<meta http-equiv="Content-Security-Policy"
content="frame-src 'self' https://www.youtube.com https://maps.google.com;">
<iframe
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="YouTube video"
width="560"
height="315">
</iframe>
Older method to prevent clickjacking (replaced by CSP frame-ancestors):
X-Frame-Options : SAMEORIGIN
X-Frame-Options : ALLOW-FROM https://trusted-site.com
Use postMessage() API for secure cross-origin communication:
Interactive code playground requires JavaScript. Here's the code:
<!-- Parent page -->
<iframe
id="child-frame"
src="https://child-domain.com"
title="Child frame">
</iframe>
<script>
const iframe = document.getElementById('child-frame');
// Send message to iframe
iframe.contentWindow.postMessage({
type: 'greeting',
message: 'Hello from parent'
}, 'https://child-domain.com');
// Receive messages from iframe
window.addEventListener('message', (event) => {
// CRITICAL: Always verify origin!
if (event.origin !== 'https://child-domain.com') {
return;
}
console.log('Received:', event.data);
});
</script>
<!-- Inside iframe (child-domain.com) -->
<script>
// Receive messages from parent
window.addEventListener('message', (event) => {
// CRITICAL: Verify origin!
if (event.origin !== 'https://parent-domain.com') {
return;
}
console.log('Parent said:', event.data.message);
// Send response
event.source.postMessage({
type: 'response',
message: 'Hello from child'
}, event.origin);
});
</script>
Interactive code playground requires JavaScript. Here's the code:
<!-- Responsive YouTube embed -->
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
loading="lazy">
</iframe>
</div>
Interactive code playground requires JavaScript. Here's the code:
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3024.2219901290355!2d-74.00369368400567!3d40.71312937933155!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x89c25a316e2e20c7%3A0xb07b3ba2cc25e3!2sOne%20World%20Trade%20Center!5e0!3m2!1sen!2sus!4v1234567890123!5m2!1sen!2sus"
width="600"
height="450"
style="border:0;"
allowfullscreen=""
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
title="Google Maps - One World Trade Center">
</iframe>
Interactive code playground requires JavaScript. Here's the code:
<style>
.iframe-container {
position: relative;
padding-bottom: 56.25%; /* 16:9 aspect ratio */
height: 0;
overflow: hidden;
max-width: 100%;
}
.iframe-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
/* 4:3 aspect ratio */
.iframe-container.ratio-4-3 {
padding-bottom: 75%;
}
/* 1:1 aspect ratio */
.iframe-container.ratio-1-1 {
padding-bottom: 100%;
}
</style>
<div class="iframe-container">
<iframe
src="https://example.com"
title="Responsive iframe"
loading="lazy">
</iframe>
</div>
Interactive code playground requires JavaScript. Here's the code:
<!-- Inline HTML content -->
<iframe
srcdoc="
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: Arial;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
</style>
</head>
<body>
<h1>Inline Content</h1>
<p>This content is defined inline using srcdoc.</p>
</body>
</html>
"
sandbox="allow-scripts"
title="Inline content example"
width="100%"
height="200">
</iframe>
Interactive code playground requires JavaScript. Here's the code:
<!-- CodeSandbox embed -->
<iframe
src="https://codesandbox.io/embed/vanilla?fontsize=14&hidenavigation=1&theme=dark"
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
title="Code Sandbox Example"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts">
</iframe>
Interactive code playground requires JavaScript. Here's the code:
<!-- Twitter/X embed -->
<iframe
src="https://platform.twitter.com/embed/Tweet.html?id=123456789"
width="550"
height="250"
style="border: 1px solid #ccc; border-radius: 4px;"
title="Twitter post"
loading="lazy">
</iframe>
<!-- Instagram embed (simplified) -->
<iframe
src="https://www.instagram.com/p/ABC123/embed"
width="400"
height="480"
frameborder="0"
scrolling="no"
allowtransparency="true"
title="Instagram post"
loading="lazy">
</iframe>
Interactive code playground requires JavaScript. Here's the code:
<!-- Lazy load iframes below the fold -->
<iframe
src="https://example.com"
loading="lazy"
title="Lazy loaded content"
width="600"
height="400">
</iframe>
<!-- Eager load critical iframes -->
<iframe
src="https://critical-content.com"
loading="eager"
title="Critical content"
width="600"
height="400">
</iframe>
Loading Strategies:
loading="lazy": Load when near viewport (default for off-screen iframes)
loading="eager": Load immediately
No attribute: Browser decides (usually immediate)
<!-- Low priority iframe -->
src = " https://ads.example.com "
<!-- High priority iframe -->
src = " https://critical-app.com "
Interactive code playground requires JavaScript. Here's the code:
<!-- Preconnect to iframe origin -->
<link rel="preconnect" href="https://www.youtube.com">
<link rel="dns-prefetch" href="https://www.youtube.com">
<!-- Prefetch iframe content -->
<link rel="prefetch" href="https://example.com/iframe-content.html">
<iframe
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="YouTube video"
loading="lazy">
</iframe>
Interactive code playground requires JavaScript. Here's the code:
<style>
.styled-iframe {
width: 100%;
height: 400px;
border: 3px solid #3b82f6;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.no-border {
border: none;
}
.with-padding {
padding: 20px;
background: #f3f4f6;
}
</style>
<div class="with-padding">
<iframe
src="https://example.com"
class="styled-iframe no-border"
title="Styled iframe">
</iframe>
</div>
Interactive code playground requires JavaScript. Here's the code:
<style>
.iframe-wrapper {
position: relative;
width: 100%;
height: 400px;
}
.iframe-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 0.3s;
}
.iframe-wrapper iframe.loaded {
opacity: 1;
}
.iframe-wrapper .loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<div class="iframe-wrapper">
<div class="loading">Loading...</div>
<iframe
src="https://example.com"
title="Iframe with loading state"
onload="this.classList.add('loaded'); this.previousElementSibling.style.display='none';">
</iframe>
</div>
Interactive code playground requires JavaScript. Here's the code:
<iframe
id="my-iframe"
src="about:blank"
title="Accessible iframe">
</iframe>
<script>
const iframe = document.getElementById('my-iframe');
// Wait for iframe to load
iframe.addEventListener('load', () => {
// Access iframe's window (same-origin only!)
const iframeWindow = iframe.contentWindow;
// Access iframe's document (same-origin only!)
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
// Modify iframe content
iframeDoc.body.innerHTML = '<h1>Modified Content</h1>';
});
</script>
Interactive code playground requires JavaScript. Here's the code:
<button onclick="createIframe()">Create Iframe</button>
<div id="container"></div>
<script>
function createIframe() {
const iframe = document.createElement('iframe');
iframe.src = 'https://example.com';
iframe.title = 'Dynamically created iframe';
iframe.width = '600';
iframe.height = '400';
iframe.setAttribute('sandbox', 'allow-scripts');
iframe.setAttribute('loading', 'lazy');
document.getElementById('container').appendChild(iframe);
}
</script>
Interactive code playground requires JavaScript. Here's the code:
<!-- Parent page -->
<iframe
id="resizable-iframe"
src="child-page.html"
style="width: 100%; border: 1px solid #ccc;"
title="Auto-resizing iframe">
</iframe>
<script>
// Receive height updates from iframe
window.addEventListener('message', (event) => {
// Verify origin
if (event.origin !== 'https://trusted-domain.com') return;
if (event.data.type === 'resize') {
const iframe = document.getElementById('resizable-iframe');
iframe.style.height = event.data.height + 'px';
}
});
</script>
<!-- Inside iframe (child-page.html) -->
<script>
function sendHeight() {
const height = document.body.scrollHeight;
window.parent.postMessage({
type: 'resize',
height: height
}, 'https://parent-domain.com');
}
// Send height on load and resize
window.addEventListener('load', sendHeight);
window.addEventListener('resize', sendHeight);
// Send height when content changes
new ResizeObserver(sendHeight).observe(document.body);
</script>
src = " https://www.youtube.com/embed/dQw4w9WgXcQ "
title = " Rick Astley - Never Gonna Give You Up (Official Video) "
src = " https://maps.google.com/maps?q=london&output=embed "
title = " Google Maps showing London, United Kingdom " >
<!-- NO title - screen readers don't know what this is -->
src = " https://www.youtube.com/embed/dQw4w9WgXcQ "
<!-- Generic title - not helpful -->
src = " https://maps.google.com "
Interactive code playground requires JavaScript. Here's the code:
<!-- Skip iframe in tab order if not interactive -->
<iframe
src="https://example.com"
title="Decorative banner"
tabindex="-1">
</iframe>
<!-- Allow focus for interactive content (default) -->
<iframe
src="https://app.example.com"
title="Interactive application">
</iframe>
Interactive code playground requires JavaScript. Here's the code:
<!-- Advertisement iframe -->
<iframe
src="https://ads.example.com"
title="Advertisement"
role="complementary"
aria-label="Sponsored advertisement">
</iframe>
<!-- Application iframe -->
<iframe
src="https://app.example.com"
title="Document Editor"
role="application"
aria-label="Online document editor">
</iframe>
Interactive code playground requires JavaScript. Here's the code:
<iframe
src="https://example.com"
title="Example content">
<p>
Your browser does not support iframes.
<a href="https://example.com">View content here</a>.
</p>
</iframe>
Feature Chrome Firefox Safari Edge Basic <iframe> 1+ 1+ 1+ 12+ sandbox4+ 17+ 5+ 10+ sandbox tokensVaries Varies Varies Varies allow (Permissions Policy)60+ 74+ 11.1+ 79+ loading77+ 77+ 16.4+ 79+ srcdoc20+ 25+ 6+ 79+ referrerpolicy51+ 50+ 11.1+ 79+ csp61+ ❌ ❌ 79+
Error : Refused to display 'https://example.com' in a frame because it set 'X-Frame-Options' to 'deny'.
Solution : The target site prevents embedding. You cannot override this. Options:
Contact site owner for permission
Use site’s official embed API if available
Link to content instead of embedding
Error : Blocked a frame from accessing a cross-origin frame.
Solution : Use postMessage() for cross-origin communication. You cannot directly access cross-origin iframe content.
Error : Mixed Content: The page was loaded over HTTPS, but requested an insecure frame.
Solution : Always use HTTPS for iframe src when parent page is HTTPS:
< iframe src = " http://example.com " ></ iframe >
< iframe src = " https://example.com " ></ iframe >
Solution : Use aspect ratio padding technique:
Interactive code playground requires JavaScript. Here's the code:
<style>
.responsive-iframe {
position: relative;
padding-bottom: 56.25%; /* 16:9 */
height: 0;
}
.responsive-iframe iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
<div class="responsive-iframe">
<iframe
src="https://example.com"
title="Responsive iframe">
</iframe>
</div>