← All Documentation
Components & Templates
TerraPDF provides two interfaces for structuring and reusing document content:
| Interface | Scope | Purpose |
|---|---|---|
IComponent |
Container slot | Reusable content block injected anywhere in a layout |
IDocument |
Whole document | Reusable, self-contained document template |
Both live in the TerraPDF.Infra namespace.
IComponent — Reusable Content Blocks
IComponent encapsulates a piece of content that can be composed into any
IContainer slot. Ideal for repeated UI elements like header cards, badges,
callout boxes, or address blocks.
Interface
namespace TerraPDF.Infra;
public interface IComponent
{
void Compose(IContainer container);
}
Example — Callout box
using TerraPDF.Core;
using TerraPDF.Helpers;
using TerraPDF.Infra;
public class CalloutBox : IComponent
{
private readonly string _text;
private readonly string _color;
public CalloutBox(string text, string color = "#E3F2FD")
{
_text = text;
_color = color;
}
public void Compose(IContainer container) =>
container
.Margin(6)
.Background(_color)
.Border(1, Color.Blue.Lighten2)
.Padding(10)
.Text(_text).Italic().FontColor(Color.Blue.Darken2);
}
Usage
col.Item().Component(new CalloutBox("Note: prices exclude VAT."));
col.Item().Component(new CalloutBox("Warning: read before proceeding.", Color.Orange.Medium));
Example — Address block
public class AddressBlock : IComponent
{
private readonly string _name;
private readonly string[] _lines;
public AddressBlock(string name, params string[] lines)
{
_name = name;
_lines = lines;
}
public void Compose(IContainer container)
{
container.Column(col =>
{
col.Spacing(2);
col.Item().Text(_name).Bold();
foreach (var line in _lines)
col.Item().Text(line).FontColor(Color.Grey.Darken1);
});
}
}
// Usage
row.RelativeItem().Component(new AddressBlock(
"Acme Corp.",
"88 Commerce Blvd, Floor 12",
"New York, NY 10001",
"billing@acme.example"
));
IDocument — Reusable Document Templates
IDocument encapsulates an entire multi-page document. Use it to separate
document structure from data and to enable unit testing.
Interface
namespace TerraPDF.Infra;
public interface IDocument
{
void Compose(IDocumentContainer container);
}
Example — Invoice template
using TerraPDF.Core;
using TerraPDF.Helpers;
using TerraPDF.Infra;
public record InvoiceData(string Number, string ClientName, decimal Total);
public class InvoiceDocument : IDocument
{
private readonly InvoiceData _data;
public InvoiceDocument(InvoiceData data) => _data = data;
public void Compose(IDocumentContainer container)
{
container.Page(page =>
{
page.Size(PageSize.A4);
page.Margin(2, Unit.Centimetre);
page.DefaultTextStyle(s => s.FontSize(11));
page.Header().Column(col =>
{
col.Item()
.Background(Color.Blue.Darken2)
.Padding(12)
.Text($"INVOICE #{_data.Number}")
.Bold().FontSize(18).FontColor(Color.White);
});
page.Content().Column(col =>
{
col.Spacing(10);
col.Item().Text($"Bill To: {_data.ClientName}").Bold();
col.Item().Text($"Total Due: ${_data.Total:N2}").FontSize(14);
});
page.Footer().AlignCenter().Text(t =>
{
t.Span("Page ").FontSize(9).FontColor(Color.Grey.Medium);
t.CurrentPageNumber().FontSize(9).FontColor(Color.Grey.Medium);
});
});
}
}
Generating the document
var data = new InvoiceData("2025-042", "Acme Corp.", 14_250.00m);
// To file
Document.Create(new InvoiceDocument(data)).PublishPdf("invoice.pdf");
// To byte array
byte[] pdf = Document.Create(new InvoiceDocument(data)).PublishPdf();
// To stream
Document.Create(new InvoiceDocument(data)).PublishPdf(responseStream);
Combining IDocument with IComponent
Components can be used freely inside IDocument.Compose:
public class ReportDocument : IDocument
{
public void Compose(IDocumentContainer container)
{
container.Page(page =>
{
page.Size(PageSize.A4);
page.Margin(2, Unit.Centimetre);
page.Content().Column(col =>
{
col.Spacing(12);
col.Item().Component(new CalloutBox("This report is confidential."));
col.Item().Text("Report body...").Justify();
});
});
}
}