Content Components
Master images, SVG graphics, lists, tables, and embedded content to create rich, data-driven PDF documents.
Table of Contents
- Images - Formats, sizing, positioning, local/remote, data binding
- SVG Basics - SVG overview, inline vs files, sizing
- SVG Drawing - Shapes, paths, styling, data binding, charts
- Lists - Ordered/unordered lists, styling, nesting, data binding
- Tables - Basics - Structure, styling, borders, column widths
- Tables - Advanced - Dynamic data, calculations, spanning, page breaks
- Attachments & Embedded Content - File attachments, embed/iframe
- Content Best Practices - Optimization, performance, accessibility
Overview
Content components are the building blocks of engaging PDF documents. This series teaches you how to work with images, create dynamic SVG graphics, structure data in tables, format lists, and embed external content for modular document composition.
What Content Can You Include?
Scryber supports a rich variety of content types:
- Images - PNG, JPEG, GIF, and SVG from local or remote sources
- SVG Graphics - Scalable vector graphics for charts, diagrams, and icons
- Tables - Structured data with headers, footers, and data binding
- Lists - Ordered, unordered, and definition lists
- Attachments - Embed files within the PDF
- External Content - Include content from other files
Quick Example
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<style>
img {
max-width: 100%;
height: auto;
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background-color: #2563eb;
color: white;
padding: 10pt;
}
td {
padding: 8pt;
border-bottom: 1pt solid #e5e7eb;
}
tr:nth-child(even) {
background-color: #f9fafb;
}
</style>
</head>
<body>
<h1>Sales Report</h1>
<!-- Image -->
<img src="{{company.logo}}" alt="Company Logo" style="width: 150pt;" />
<!-- SVG Chart -->
<svg width="400" height="200">
<rect x="0" y="{{calc(200, '-', sales.q1)}}"
width="80" height="{{sales.q1}}" fill="#3b82f6" />
<rect x="100" y="{{calc(200, '-', sales.q2)}}"
width="80" height="{{sales.q2}}" fill="#3b82f6" />
<rect x="200" y="{{calc(200, '-', sales.q3)}}"
width="80" height="{{sales.q3}}" fill="#3b82f6" />
<rect x="300" y="{{calc(200, '-', sales.q4)}}"
width="80" height="{{sales.q4}}" fill="#3b82f6" />
</svg>
<!-- Dynamic Table -->
<table>
<thead>
<tr>
<th>Product</th>
<th>Sales</th>
<th>Revenue</th>
</tr>
</thead>
<tbody>
{{#each products}}
<tr>
<td>{{this.name}}</td>
<td>{{this.sales}}</td>
<td>${{this.revenue}}</td>
</tr>
{{/each}}
</tbody>
</table>
</body>
</html>
What You’ll Learn
This series covers all content components comprehensively:
1. Images
- Image formats (PNG, JPEG, GIF, SVG)
- Image sizing and positioning
- Local vs remote images
- Image styling (borders, margins, alignment)
- Data binding image sources
- Base64 embedded images
2. SVG Basics
- SVG element overview
- Inline SVG vs SVG files
- SVG sizing and viewBox
- SVG positioning and styling
3. SVG Drawing
- SVG shapes (rect, circle, ellipse, polygon, path)
- SVG lines and polylines
- SVG text elements
- SVG styling and attributes
- Data binding in SVG
- Dynamic charts and visualizations
4. Lists
- Ordered lists (ol) and unordered lists (ul)
- List styling and custom markers
- Nested lists
- Definition lists
- List data binding
5. Tables - Basics
- Table structure (thead, tbody, tfoot)
- Rows and columns
- Table borders and styling
- Cell spacing, padding, and alignment
- Column widths and groups
6. Tables - Advanced
- Dynamic table rows with data binding
- Template binding in tables
- Calculated columns
- Spanning cells (colspan, rowspan)
- Repeating headers on pages
- Table page breaks
7. Attachments & Embedded Content
- File attachments (object element)
- Attachment icons and styling
- Embedding files in PDFs
- Data-bound attachments
- Embed and iframe elements
- Content inclusion and modular documents
8. Content Best Practices
- Performance optimization
- Image and SVG optimization
- Table performance
- Accessibility considerations
- Common patterns and troubleshooting
Prerequisites
Before starting this series:
- Complete Getting Started - Basic Scryber knowledge
- Review Data Binding - For dynamic content
- Review Styling - For content styling
Key Concepts
Image Sources
<!-- Local file -->
<img src="./images/logo.png" />
<!-- Remote URL -->
<img src="https://example.com/image.jpg" />
<!-- Data binding -->
<img src="{{product.imageUrl}}" />
<!-- Base64 embedded -->
<img src="data:image/png;base64,iVBORw0KG..." />
SVG Inline vs External
Inline SVG - Full control and data binding:
<svg width="200" height="200">
<circle cx="100" cy="100" r="{{radius}}" fill="blue" />
</svg>
External SVG - Reusable graphics:
<img src="./graphics/chart.svg" />
Table Structure
<table>
<thead>
<!-- Column headers (repeats on each page) -->
<tr>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<!-- Data rows -->
<tr>
<td>Data 1</td>
<td>Data 2</td>
</tr>
</tbody>
<tfoot>
<!-- Table footer -->
<tr>
<td>Total</td>
<td>Sum</td>
</tr>
</tfoot>
</table>
Dynamic Content with Data Binding
Dynamic Images
{{#each products}}
<div class="product">
<img src="{{this.imageUrl}}"
alt="{{this.name}}"
style="width: 100pt; height: 100pt;" />
<h3>{{this.name}}</h3>
<p>{{this.description}}</p>
</div>
{{/each}}
Data-Driven SVG Charts
<svg width="500" height="300">
{{#each dataPoints}}
<rect x="{{calc(@index, '*', 50)}}"
y="{{calc(300, '-', this.value)}}"
width="40"
height="{{this.value}}"
fill="#3b82f6" />
<text x="{{calc(@index, '*', 50, '+', 20)}}"
y="290"
text-anchor="middle">
{{this.label}}
</text>
{{/each}}
</svg>
Dynamic Tables with Calculations
<table>
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{this.name}}</td>
<td>{{this.quantity}}</td>
<td>${{this.price}}</td>
<td>${{calc(this.quantity, '*', this.price)}}</td>
</tr>
{{/each}}
</tbody>
</table>
Real-World Examples
Product Catalog
<div class="catalog">
{{#each products}}
<div class="product-card" style="page-break-inside: avoid;">
<img src="{{this.imageUrl}}"
style="width: 200pt; height: 200pt; object-fit: cover;" />
<h3>{{this.name}}</h3>
<p>{{this.description}}</p>
<ul>
{{#each this.features}}
<li>{{this}}</li>
{{/each}}
</ul>
<p class="price">${{this.price}}</p>
</div>
{{/each}}
</div>
Data Dashboard
<div class="dashboard">
<h1>Sales Dashboard - {{reportDate}}</h1>
<!-- KPI Cards with SVG Icons -->
<div class="kpi-grid">
<div class="kpi-card">
<svg width="50" height="50">
<circle cx="25" cy="25" r="20" fill="#10b981" />
<text x="25" y="30" text-anchor="middle" fill="white">$</text>
</svg>
<h3>Total Revenue</h3>
<p class="kpi-value">${{totalRevenue}}</p>
</div>
</div>
<!-- Bar Chart -->
<svg width="600" height="400">
<text x="300" y="20" text-anchor="middle" font-size="16pt">
Quarterly Sales
</text>
{{#each quarters}}
<rect x="{{calc(@index, '*', 150, '+', 50)}}"
y="{{calc(350, '-', this.sales)}}"
width="100"
height="{{this.sales}}"
fill="#3b82f6" />
<text x="{{calc(@index, '*', 150, '+', 100)}}"
y="370"
text-anchor="middle">
Q{{calc(@index, '+', 1)}}
</text>
<text x="{{calc(@index, '*', 150, '+', 100)}}"
y="{{calc(350, '-', this.sales, '-', 10)}}"
text-anchor="middle">
${{this.sales}}
</text>
{{/each}}
</svg>
<!-- Data Table -->
<table>
<thead>
<tr>
<th>Region</th>
<th>Sales</th>
<th>Growth</th>
</tr>
</thead>
<tbody>
{{#each regions}}
<tr>
<td>{{this.name}}</td>
<td>${{this.sales}}</td>
<td style="color: {{if(this.growth > 0, 'green', 'red')}}">
{{this.growth}}%
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
Invoice with Attachments
<div class="invoice">
<img src="{{company.logo}}" style="width: 150pt;" />
<h1>Invoice #{{invoice.number}}</h1>
<table class="invoice-table">
<thead>
<tr>
<th>Description</th>
<th>Quantity</th>
<th>Price</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{{#each invoice.items}}
<tr>
<td>{{this.description}}</td>
<td>{{this.quantity}}</td>
<td>${{this.price}}</td>
<td>${{calc(this.quantity, '*', this.price)}}</td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td colspan="3"><strong>Total</strong></td>
<td><strong>${{invoice.total}}</strong></td>
</tr>
</tfoot>
</table>
<!-- Attach receipt -->
{{#if invoice.receiptPath}}
<div class="attachment">
<object id="receipt"
data-file="{{invoice.receiptPath}}"
type="application/attachment"
data-icon="PaperClip"></object>
<a href="#receipt">View Receipt</a>
</div>
{{/if}}
</div>
Performance Tips
Optimize Images
<!-- ❌ Large, unoptimized image -->
<img src="photo.jpg" /> <!-- 5MB file -->
<!-- ✅ Optimized, appropriately sized -->
<img src="photo-optimized.jpg" style="width: 200pt;" /> <!-- 100KB -->
SVG vs Raster Images
<!-- ✅ Use SVG for logos and icons (scales perfectly) -->
<img src="logo.svg" style="width: 100pt;" />
<!-- ✅ Use PNG/JPEG for photos (better file size) -->
<img src="photo.jpg" style="width: 300pt;" />
Table Performance
<!-- ✅ Specify column widths for faster rendering -->
<table>
<colgroup>
<col style="width: 40%;" />
<col style="width: 30%;" />
<col style="width: 30%;" />
</colgroup>
<tbody>
<!-- table rows -->
</tbody>
</table>
Learning Path
Recommended progression:
- Start with Images - Understand image handling
- Learn SVG Basics - Vector graphics fundamentals
- Create SVG Graphics - Data-driven visualizations
- Master Lists - Structured content
- Build Tables - Tabular data basics
- Advanced Tables - Dynamic data and calculations
- Add Attachments - Embed files and external content
- Apply Best Practices - Optimization and performance
Tips for Success
- Optimize Images First - Resize before embedding
- Use SVG for Scalability - Logos, icons, and charts
- Data Bind Dynamically - Let data drive content
- Specify Table Widths - Improves performance
- Test with Real Data - Varying data sizes
- Use Relative Units - More flexible layouts
- Break Large Tables - Consider pagination
- Cache Remote Content - Improve generation speed
Common Patterns
Image Gallery
<div class="gallery">
{{#each images}}
<div class="gallery-item">
<img src="{{this.url}}"
alt="{{this.caption}}"
style="width: 200pt; height: 150pt; object-fit: cover;" />
<p>{{this.caption}}</p>
</div>
{{/each}}
</div>
Chart with Legend
<div class="chart-container">
<svg width="500" height="300">
<!-- Chart drawing -->
</svg>
<ul class="legend">
{{#each series}}
<li>
<svg width="20" height="20">
<rect width="20" height="20" fill="{{this.color}}" />
</svg>
{{this.label}}
</li>
{{/each}}
</ul>
</div>
Running Totals in Table
<var data-id="runningTotal" data-value="0" />
<table>
<tbody>
{{#each transactions}}
<tr>
<td>{{this.date}}</td>
<td>{{this.description}}</td>
<td>${{this.amount}}</td>
<var data-id="runningTotal"
data-value="{{calc(Document.Params.runningTotal, '+', this.amount)}}" />
<td>${{Document.Params.runningTotal}}</td>
</tr>
{{/each}}
</tbody>
</table>
Next Steps
Ready to master content components? Start with Images to learn about image handling and optimization.
Jump to specific topics:
- SVG Drawing for data-driven graphics
- Tables - Advanced for dynamic tables
- Attachments & Embedded Content for file embedding
Related Series:
- Data Binding - Dynamic content
- Styling & Appearance - Content styling
- Practical Applications - Real-world examples
Begin with content components → Images