<iframe> and <embed> : The Embedded Content Elements
The <iframe> and <embed> elements allow embedding external content into PDF documents. They support loading remote HTML files that are dynamically parsed and embedded at render time. These elements enable content reuse, modular document composition, and dynamic content inclusion.
On this page
- Usage
- Supported Attributes
- Notes
- Examples
- Basic Content Inclusion
- Modular Document Composition
- Dynamic Content Loading
- Styled Iframe with Dimensions
- Iframe with Passthrough Styling
- Conditional Content Loading
- Loading Remote Content
- Multi-Language Support
- Nested Iframes
- Template Variations
- Iframe with Fallback Content
- Reusable Components
- Dynamic Report Sections
- Themed Document Assembly
- Page-Specific Headers/Footers
- Email Template Embedding
- Form Components
- API-Driven Content
- Responsive Container Sizing
- Conditional Regional Content
- Complex Document Structure
- See Also
Usage
The <iframe> and <embed> elements enable embedded content that:
- Load and parse external HTML documents via the
srcattribute - Support remote content loading from URLs or local file paths
- Parse and render external content within the current document context
- Support styling through CSS and inline styles
- Allow dynamic content sources through data binding
- Support visibility control and conditional rendering
- Enable document composition from multiple sources
- Can be nested within any container element
- Support passthrough styling mode for iframe content
<!-- Basic iframe loading external HTML -->
<iframe src="header.html"></iframe>
<!-- Embed element with external content -->
<embed src="footer.html" />
<!-- Styled iframe with dimensions -->
<iframe src="content.html" style="width: 100%; min-height: 400pt;"></iframe>
Supported Attributes
Standard HTML Attributes
| Attribute | Type | Description |
|---|---|---|
id |
string | Unique identifier for the element. |
class |
string | CSS class name(s) for styling. Multiple classes separated by spaces. |
style |
string | Inline CSS styles applied directly to the element. |
title |
string | Sets the outline/bookmark title for the embedded content. |
hidden |
string | Controls visibility. Set to “hidden” to hide the element, or omit/empty to show. |
Embedded Content Attributes
| Attribute | Type | Description |
|---|---|---|
src |
string | Required. Source URL or file path for the external content to load and parse. |
data-passthrough |
boolean | (iframe only) If true, parent styles pass through to embedded content. Default: false. |
CSS Style Support
Both <iframe> and <embed> elements support extensive CSS styling:
Sizing:
width,height,min-width,max-width,min-height,max-height
Positioning:
display:block(default),inline,inline-block,noneposition:static,relative,absolutefloat:left,right,noneclear:both,left,right,nonetop,left,right,bottom(for positioned elements)
Spacing:
margin,margin-top,margin-right,margin-bottom,margin-leftpadding(all variants)
Visual Effects:
border,border-width,border-color,border-style,border-radiusbackground,background-coloropacity
Notes
How Embedded Content Works in PDF
Unlike web browsers where iframes create separate browsing contexts, Scryber’s <iframe> and <embed> elements work as content inclusion mechanisms:
- Parse-Time Loading: External content is fetched and parsed during document generation
- Content Merging: The parsed content becomes part of the parent document’s content tree
- No Sandboxing: Embedded content shares the same PDF document context
- Style Inheritance: Styles can be controlled via the
data-passthroughattribute (iframe only) - Static Inclusion: Content is resolved at generation time, not at viewing time
This approach is similar to server-side includes (SSI) or template partials rather than browser iframe behavior.
iframe vs embed
Both elements function similarly with one key difference:
iframe:
- Extends the
Divcomponent - Supports
data-passthroughattribute for style control - By default, isolates embedded content from parent styles (passthrough=false)
- Can contain fallback content in its body
- Best for complete HTML documents or sections
embed:
- Extends
VisualComponentdirectly - Always inherits parent styles
- Simpler component model
- Typically used for smaller content fragments
- Best for reusable snippets and partials
External Content Sources
The src attribute supports multiple source types:
- Relative File Paths:
<iframe src="partials/header.html"></iframe> <embed src="../shared/footer.html" /> - Absolute File Paths:
<iframe src="/templates/navigation.html"></iframe> - Remote URLs:
<iframe src="https://example.com/content.html"></iframe> <embed src="https://api.example.com/template?id=123" /> -
Dynamic Sources via Data Binding:
<iframe src="{{model.contentUrl}}"></iframe>
Supported Content Types
The embedded content source should be valid HTML that Scryber can parse:
- HTML Documents: Complete HTML with
<html>,<head>, and<body>tags - HTML Fragments: Partial HTML containing just body content
- XML Documents: Well-formed XML that follows Scryber’s namespace conventions
- PDF Templates: Other PDF template files in HTML format
Content must be parseable by Scryber’s HTML parser. Standard HTML5 elements and Scryber-specific components are supported.
Style Passthrough (iframe only)
The data-passthrough attribute controls style inheritance for iframe elements:
passthrough=”false” (default):
- Embedded content renders with isolated styles
- Parent document styles do not affect embedded content
- Embedded content uses only its own defined styles
- Useful for completely independent content blocks
passthrough=”true”:
- Parent styles are applied to embedded content
- Embedded content inherits typography, colors, and other styles
- Allows consistent theming across embedded content
- Useful for themed document composition
<!-- Isolated styling (default) -->
<iframe src="content.html"></iframe>
<!-- Inherit parent styles -->
<iframe src="content.html" data-passthrough="true"></iframe>
Remote Content Loading
When using remote URLs, consider:
- Network Access: Scryber must have network access to fetch remote content
- Performance: Remote content loading adds network latency to document generation
- Caching: Consider implementing caching mechanisms for frequently used remote content
- Error Handling: Use proper error handling for failed remote requests
- Security: Validate and trust remote content sources
Error Handling
When external content fails to load:
- In Strict conformance mode: An error is thrown, stopping document generation
- In Lax conformance mode: The error is logged and generation continues
- Use try-catch blocks or conformance settings to handle loading failures gracefully
Content Security
When embedding external content:
- Trust Content Sources: Only embed content from trusted sources
- Validate URLs: Sanitize and validate dynamic URL sources
- Input Validation: Validate any user-provided source paths
- Local File Access: Be cautious with local file system access in web applications
Fallback Content
The <iframe> element can contain fallback content displayed if loading fails:
<iframe src="content.html">
<p>This content will be shown if content.html fails to load</p>
</iframe>
Note: With <embed> being a self-closing element, fallback content should be handled externally.
Class Hierarchy
In the Scryber codebase:
HTMLiFrame:
- Extends
Div→Panel→ContainerComponent→VisualComponent - Decorated with
[PDFRemoteParsableComponent("iframe", SourceAttribute = "src")] - Supports
data-passthroughfor style isolation control - Default display mode:
block
HTMLEmbed:
- Extends
VisualComponent→Component - Decorated with
[PDFRemoteParsableComponent("embed", SourceAttribute = "src")] - Implements
IInvisibleContainerinterface - Simpler component model without style isolation
Examples
Basic Content Inclusion
<!-- Load header from external file -->
<iframe src="templates/header.html"></iframe>
<div class="content">
<h1>Main Document Content</h1>
<p>This is the main document content...</p>
</div>
<!-- Load footer from external file -->
<embed src="templates/footer.html" />
Modular Document Composition
<!DOCTYPE html>
<html>
<head>
<title>Modular Report</title>
<style>
body { font-family: Arial, sans-serif; }
.section { margin: 20pt 0; }
</style>
</head>
<body>
<!-- Company header -->
<iframe src="partials/company-header.html"></iframe>
<!-- Executive summary -->
<div class="section">
<iframe src="reports/executive-summary.html"></iframe>
</div>
<!-- Financial data -->
<div class="section">
<iframe src="reports/financial-data.html"></iframe>
</div>
<!-- Charts and graphs -->
<div class="section">
<iframe src="reports/charts.html"></iframe>
</div>
<!-- Legal footer -->
<embed src="partials/legal-footer.html" />
</body>
</html>
Dynamic Content Loading
<!-- With model = { headerTemplate: "header-v2.html", footerTemplate: "footer-standard.html" } -->
<iframe src="{{model.headerTemplate}}"></iframe>
<div class="main-content">
<h1>{{model.title}}</h1>
<p>{{model.description}}</p>
</div>
<iframe src="{{model.footerTemplate}}"></iframe>
Styled Iframe with Dimensions
<style>
.embedded-content {
width: 100%;
min-height: 300pt;
border: 1pt solid #ccc;
padding: 15pt;
background-color: #f9f9f9;
}
</style>
<iframe src="content/article.html" class="embedded-content"></iframe>
Iframe with Passthrough Styling
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: 'Helvetica', sans-serif;
color: #333;
font-size: 11pt;
}
h1 { color: #336699; }
h2 { color: #5588bb; }
</style>
</head>
<body>
<!-- Content inherits parent styles -->
<iframe src="section1.html" data-passthrough="true"></iframe>
<!-- Content uses its own styles only -->
<iframe src="section2.html" data-passthrough="false"></iframe>
<!-- Default behavior (no passthrough) -->
<iframe src="section3.html"></iframe>
</body>
</html>
Conditional Content Loading
<!-- With model = { showHeader: true, showFooter: false } -->
<iframe src="header.html" hidden="{{model.showHeader ? '' : 'hidden'}}"></iframe>
<div class="content">
<h1>Document Content</h1>
</div>
<iframe src="footer.html" hidden="{{model.showFooter ? '' : 'hidden'}}"></iframe>
Loading Remote Content
<!-- Load from remote API -->
<iframe src="https://api.example.com/templates/header?format=html"></iframe>
<!-- Load from CDN -->
<embed src="https://cdn.example.com/shared/footer.html" />
<!-- Load from internal network -->
<iframe src="http://internal.company.com/templates/disclaimer.html"></iframe>
Multi-Language Support
<!-- With model = { language: "en", region: "US" } -->
<iframe src="i18n/{{model.language}}/header.html"></iframe>
<div class="content">
<iframe src="i18n/{{model.language}}/{{model.region}}/content.html"></iframe>
</div>
<iframe src="i18n/{{model.language}}/footer.html"></iframe>
Nested Iframes
<!-- main-document.html -->
<div>
<h1>Main Document</h1>
<iframe src="section-with-subsections.html"></iframe>
</div>
<!-- section-with-subsections.html -->
<div class="section">
<h2>Section Title</h2>
<iframe src="subsection-a.html"></iframe>
<iframe src="subsection-b.html"></iframe>
</div>
Template Variations
<!-- With model = { templateVersion: 2, customerType: "premium" } -->
<iframe src="headers/header-v{{model.templateVersion}}.html"></iframe>
<div class="main-content">
<!-- Customer-specific content -->
<iframe src="content/{{model.customerType}}/main.html"></iframe>
</div>
<iframe src="footers/footer-{{model.customerType}}.html"></iframe>
Iframe with Fallback Content
<iframe src="remote-content.html">
<!-- Fallback content if loading fails -->
<div style="padding: 20pt; background-color: #fff3cd; border: 1pt solid #ffc107;">
<h3 style="margin-top: 0;">Content Unavailable</h3>
<p>The remote content could not be loaded. This is fallback content.</p>
</div>
</iframe>
Reusable Components
<!-- Load reusable table header -->
<table style="width: 100%;">
<thead>
<tr>
<embed src="components/table-header.html" />
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
</tr>
</tbody>
</table>
Dynamic Report Sections
<!-- With model.sections = [{src: "intro.html"}, {src: "analysis.html"}, {src: "conclusion.html"}] -->
<div class="report">
<h1>{{model.title}}</h1>
<template data-bind="{{model.sections}}">
<div class="report-section">
<iframe src="sections/{{.src}}" style="width: 100%; margin: 15pt 0;"></iframe>
</div>
</template>
</div>
Themed Document Assembly
<!DOCTYPE html>
<html>
<head>
<style>
/* Global theme styles */
body {
font-family: 'Georgia', serif;
color: #2c3e50;
line-height: 1.6;
}
.theme-primary { color: #3498db; }
.theme-secondary { color: #2ecc71; }
</style>
</head>
<body>
<!-- All iframes with passthrough will inherit theme -->
<iframe src="sections/cover.html" data-passthrough="true"></iframe>
<iframe src="sections/toc.html" data-passthrough="true"></iframe>
<iframe src="sections/chapter1.html" data-passthrough="true"></iframe>
<iframe src="sections/chapter2.html" data-passthrough="true"></iframe>
</body>
</html>
Page-Specific Headers/Footers
<!DOCTYPE html>
<html>
<head>
<title>Multi-Section Report</title>
</head>
<body>
<!-- Section 1 with specific header -->
<div style="page-break-after: always;">
<iframe src="headers/section1-header.html"></iframe>
<div class="content">Section 1 content...</div>
</div>
<!-- Section 2 with different header -->
<div style="page-break-after: always;">
<iframe src="headers/section2-header.html"></iframe>
<div class="content">Section 2 content...</div>
</div>
<!-- Section 3 with another header -->
<div>
<iframe src="headers/section3-header.html"></iframe>
<div class="content">Section 3 content...</div>
</div>
</body>
</html>
Email Template Embedding
<!-- Load email signature from shared template -->
<div class="email-body">
<p>Dear {{model.recipientName}},</p>
<p>{{model.messageBody}}</p>
<iframe src="templates/signatures/{{model.senderDepartment}}.html"></iframe>
</div>
Form Components
<div class="application-form">
<h1>Application Form</h1>
<!-- Applicant information section -->
<iframe src="form-sections/applicant-info.html"></iframe>
<!-- Employment history section -->
<iframe src="form-sections/employment-history.html"></iframe>
<!-- References section -->
<iframe src="form-sections/references.html"></iframe>
<!-- Legal disclaimers -->
<embed src="form-sections/legal-disclaimers.html" />
</div>
API-Driven Content
<!-- With model = { apiEndpoint: "https://api.example.com", reportId: "12345" } -->
<div class="report">
<!-- Load report header from API -->
<iframe src="{{model.apiEndpoint}}/reports/{{model.reportId}}/header.html"></iframe>
<!-- Load report body from API -->
<iframe src="{{model.apiEndpoint}}/reports/{{model.reportId}}/body.html"
style="min-height: 500pt;"></iframe>
<!-- Load report footer from API -->
<iframe src="{{model.apiEndpoint}}/reports/{{model.reportId}}/footer.html"></iframe>
</div>
Responsive Container Sizing
<style>
.responsive-container {
width: 100%;
min-height: 200pt;
max-height: 600pt;
overflow: hidden;
}
</style>
<div class="responsive-container">
<iframe src="flexible-content.html" style="width: 100%; height: auto;"></iframe>
</div>
Conditional Regional Content
<!-- With model = { country: "US", state: "CA" } -->
<div class="regional-document">
<!-- Country-specific header -->
<iframe src="content/{{model.country}}/header.html"></iframe>
<!-- State/province-specific content -->
<iframe src="content/{{model.country}}/{{model.state}}/main.html"></iframe>
<!-- Country-specific footer with legal info -->
<iframe src="content/{{model.country}}/legal-footer.html"></iframe>
</div>
Complex Document Structure
<!DOCTYPE html>
<html>
<head>
<title>Annual Report</title>
</head>
<body>
<!-- Cover page -->
<div style="page-break-after: always;">
<iframe src="report/cover.html"></iframe>
</div>
<!-- Table of contents -->
<div style="page-break-after: always;">
<iframe src="report/toc.html"></iframe>
</div>
<!-- Executive summary -->
<div style="page-break-after: always;">
<iframe src="report/executive-summary.html" data-passthrough="true"></iframe>
</div>
<!-- Financial statements -->
<div style="page-break-after: always;">
<h1>Financial Statements</h1>
<iframe src="report/balance-sheet.html"></iframe>
<iframe src="report/income-statement.html"></iframe>
<iframe src="report/cash-flow.html"></iframe>
</div>
<!-- Notes to financial statements -->
<div style="page-break-after: always;">
<iframe src="report/financial-notes.html"></iframe>
</div>
<!-- Management discussion -->
<div style="page-break-after: always;">
<iframe src="report/management-discussion.html"></iframe>
</div>
<!-- Appendices -->
<div>
<h1>Appendices</h1>
<iframe src="report/appendix-a.html"></iframe>
<iframe src="report/appendix-b.html"></iframe>
<iframe src="report/appendix-c.html"></iframe>
</div>
</body>
</html>
See Also
- object - Object element for file attachments
- picture - Picture element for responsive images
- img - Image element
- div - Container element
- template - Template element for data binding
- Data Binding - Data binding and expressions
- Document Parser - HTML/XML parsing in Scryber
- Remote Resources - Loading remote content