Your First Document
Create your first PDF document from scratch using HTML and C# in minutes.
Learning Objectives
By the end of this article, you’ll be able to:
- Create a basic HTML template for PDFs
- Parse HTML documents with Scryber
- Generate and save PDF files
- Understand XHTML vs HTML5 formats
- Add basic styling to your document
Hello World PDF
Let’s create the simplest possible PDF document:
Step 1: Create the HTML Template
Create a file named hello.html:
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>This is my first PDF generated with Scryber.Core.</p>
</body>
</html>
Step 2: Generate the PDF
using Scryber.Components;
using System.IO;
class Program
{
static void Main(string[] args)
{
// Load the HTML template
var doc = Document.ParseDocument("hello.html");
// Generate the PDF
using (var stream = new FileStream("hello.pdf", FileMode.Create))
{
doc.SaveAsPDF(stream);
}
Console.WriteLine("PDF created: hello.pdf");
}
}
Step 3: Run and View
dotnet run
Open hello.pdf - you should see your first PDF!
XHTML vs HTML5 Format
Scryber supports two document formats:
XHTML Format (Recommended)
Uses XML namespace:
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<title>XHTML Document</title>
</head>
<body>
<p>Content here</p>
</body>
</html>
Parse with:
var doc = Document.ParseDocument("template.html");
Benefits:
- Full XML namespace support
- Stricter validation
- Better for complex documents
- Supports Scryber-specific namespaces
HTML5 Format
Standard HTML5 without namespace:
<!DOCTYPE html>
<html>
<head>
<title>HTML5 Document</title>
</head>
<body>
<p>Content here</p>
</body>
</html>
Parse with:
var doc = Document.ParseHTML("template.html");
Benefits:
- Familiar HTML5 syntax
- No namespace required
- Simpler for basic documents
- Works with existing HTML files
Which Should You Use?
| Use XHTML When | Use HTML5 When |
|---|---|
| Building templates from scratch | Converting existing HTML |
| Need strict validation | Prefer simpler syntax |
| Using Scryber-specific elements | Working with HTML5 tools |
| Want explicit namespace control | Don’t need custom namespaces |
Both formats produce identical PDF output!
Complete First Document Example
Let’s create a more complete document with styling:
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<title>My First PDF Document</title>
<style>
body {
font-family: 'Helvetica', sans-serif;
font-size: 11pt;
margin: 40pt;
color: #333;
}
h1 {
color: #2563eb;
font-size: 24pt;
border-bottom: 2pt solid #2563eb;
padding-bottom: 10pt;
margin-bottom: 20pt;
}
h2 {
color: #1e40af;
font-size: 18pt;
margin-top: 20pt;
margin-bottom: 10pt;
}
p {
line-height: 1.6;
margin-bottom: 10pt;
}
.highlight {
background-color: #fef3c7;
padding: 10pt;
border-left: 4pt solid #f59e0b;
margin: 15pt 0;
}
.footer {
position: fixed;
bottom: 20pt;
left: 40pt;
right: 40pt;
text-align: center;
font-size: 9pt;
color: #666;
border-top: 1pt solid #ccc;
padding-top: 10pt;
}
</style>
</head>
<body>
<h1>Welcome to Scryber.Core</h1>
<h2>Introduction</h2>
<p>
Scryber.Core is a powerful .NET library for generating PDF documents
using HTML and CSS. This document demonstrates basic features.
</p>
<h2>Key Features</h2>
<ul>
<li>HTML & CSS templating</li>
<li>Data binding with Handlebars syntax</li>
<li>No browser required</li>
<li>Full programmatic control</li>
<li>Production-ready performance</li>
</ul>
<div class="highlight">
<strong>Pro Tip:</strong> Use CSS for all styling to keep your
templates clean and maintainable.
</div>
<h2>Getting Started</h2>
<p>
Creating PDFs with Scryber is as simple as writing HTML. You already
have all the skills you need!
</p>
<div class="footer">
Page <page-number /> of <page-count /> | Generated with Scryber.Core
</div>
</body>
</html>
C# Code:
using Scryber.Components;
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
try
{
// Parse the document
var doc = Document.ParseDocument("first-document.html");
// Set document properties
doc.Info.Title = "My First PDF Document";
doc.Info.Author = "Your Name";
doc.Info.Subject = "Learning Scryber.Core";
// Generate the PDF
using (var stream = new FileStream("first-document.pdf", FileMode.Create))
{
doc.SaveAsPDF(stream);
}
Console.WriteLine("✓ PDF created successfully: first-document.pdf");
}
catch (Exception ex)
{
Console.WriteLine($"✗ Error: {ex.Message}");
}
}
}
Parsing From Different Sources
From File
// XHTML format
var doc = Document.ParseDocument("template.html");
// HTML5 format
var doc = Document.ParseHTML("template.html");
From String
string html = @"
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head><title>From String</title></head>
<body><h1>Hello!</h1></body>
</html>";
using (var reader = new StringReader(html))
{
var doc = Document.ParseDocument(reader, ParseSourceType.DynamicContent);
}
From Stream
using (var fileStream = File.OpenRead("template.html"))
{
var doc = Document.ParseDocument(fileStream, ParseSourceType.LocalFile);
}
From URL (Remote)
var doc = Document.ParseDocument(
"https://example.com/template.html",
ParseSourceType.RemoteFile
);
Saving PDFs
To File
using (var stream = new FileStream("output.pdf", FileMode.Create))
{
doc.SaveAsPDF(stream);
}
To Memory Stream (for HTTP Response)
using (var ms = new MemoryStream())
{
doc.SaveAsPDF(ms);
byte[] pdfBytes = ms.ToArray();
return File(pdfBytes, "application/pdf", "document.pdf");
}
To Response Stream (ASP.NET Core)
public IActionResult GeneratePdf()
{
var doc = Document.ParseDocument("template.html");
return new FileStreamResult(
doc.SaveAsPDF(),
"application/pdf"
)
{
FileDownloadName = "document.pdf"
};
}
Document Properties
Set metadata for your PDFs:
var doc = Document.ParseDocument("template.html");
// Document information
doc.Info.Title = "Invoice #12345";
doc.Info.Author = "Acme Corporation";
doc.Info.Subject = "Monthly Invoice";
doc.Info.Keywords = "invoice, billing, payment";
// Creator information
doc.Info.Creator = "My Application v1.0";
// Generate with metadata
doc.SaveAsPDF("invoice.pdf");
These properties appear in PDF viewers:

Common Patterns
1. Template + Data Pattern
public byte[] GeneratePdf(string templatePath, object data)
{
var doc = Document.ParseDocument(templatePath);
// Pass data to template
doc.Params["model"] = data;
using (var ms = new MemoryStream())
{
doc.SaveAsPDF(ms);
return ms.ToArray();
}
}
2. Reusable Document Service
public class PdfService
{
private readonly string _templateDirectory;
public PdfService(string templateDirectory)
{
_templateDirectory = templateDirectory;
}
public byte[] GenerateFromTemplate(string templateName, object data)
{
string templatePath = Path.Combine(_templateDirectory, templateName);
var doc = Document.ParseDocument(templatePath);
doc.Params["model"] = data;
using (var ms = new MemoryStream())
{
doc.SaveAsPDF(ms);
return ms.ToArray();
}
}
}
Usage:
var pdfService = new PdfService("./Templates");
byte[] pdf = pdfService.GenerateFromTemplate("invoice.html", invoiceData);
Try It Yourself
Exercise 1: Personal Letter
Create a PDF with:
- Your name as the title
- Three sections (Introduction, Skills, Contact)
- Different colors for each section heading
- A footer with page numbers
Exercise 2: Styled List
Create a PDF with:
- An unordered list of your favorite things
- Custom list markers using CSS
- Background colors alternating between items
- A border around the entire list
Exercise 3: Parse Methods
Create the same document three ways:
- From an
.htmlfile usingParseDocument - From a string using
StringReader - Using
ParseHTMLinstead ofParseDocument
Compare the results - they should be identical!
Common Pitfalls
❌ Forgetting the Namespace
<!-- This won't work with ParseDocument -->
<html>
<body>Hello</body>
</html>
✅ Solution: Add the namespace or use ParseHTML
<html xmlns='http://www.w3.org/1999/xhtml'>
<body>Hello</body>
</html>
❌ Not Disposing Streams
var stream = new FileStream("output.pdf", FileMode.Create);
doc.SaveAsPDF(stream);
// Stream not disposed!
✅ Solution: Use using statements
using (var stream = new FileStream("output.pdf", FileMode.Create))
{
doc.SaveAsPDF(stream);
}
❌ Relative Paths Without Context
// May not find the file
var doc = Document.ParseDocument("template.html");
✅ Solution: Use absolute or properly resolved paths
string templatePath = Path.Combine(
Directory.GetCurrentDirectory(),
"Templates",
"template.html"
);
var doc = Document.ParseDocument(templatePath);
Next Steps
Now that you can create basic documents:
- HTML to PDF - Learn which HTML elements are supported
- CSS Basics - Master styling your documents
- Data Binding - Make documents dynamic
Additional Resources
- HTML Element Reference - All supported HTML elements
- Document API - Complete API documentation
- Code Examples - More complete examples
Continue learning → HTML to PDF