Layout Elements
Compose complex page layouts using columns, rows, layers, decorations, and paging controls. Every element chains off an IContainer and can be nested arbitrarily.
Column
A Column arranges its items vertically from top to bottom. When the content exceeds the available page height, it automatically paginates — remaining items flow onto the next page.
page.Content().Column(col =>
{
col.Spacing(10);
col.Item().Text("First item");
col.Item().Text("Second item");
col.Item().Text("Third item");
});
| Method | Description |
|---|---|
col.Spacing(float, Unit) | Vertical space between items (default 0) |
col.Item() | Returns an IContainer for the next item |
Columns support any number of items. Each Item() call returns an IContainer that accepts any nested element — text, images, tables, rows, or other columns.
col.Item().Background(Color.FromHex("#EEE")).Padding(10).Text("Styled item");
col.Item().Row(row => { /* nested row */ });
col.Item().Image(logoBytes).FitWidth();
Row
A Row arranges its items horizontally. Three item types control how width is distributed.
page.Content().Row(row =>
{
row.Spacing(10);
row.ConstantItem(100).Background(Color.Grey).Text("Fixed 100pt");
row.RelativeItem(2).Background(Color.LightGrey).Text("2/3 of remaining");
row.RelativeItem(1).Background(Color.White).Text("1/3 of remaining");
row.AutoItem().Text("Fits content");
});
| Method | Description |
|---|---|
row.ConstantItem(float, Unit) | Fixed width in points (or specified unit) |
row.RelativeItem(float) | Proportional share of remaining space (default weight: 1) |
row.AutoItem() | Width determined by child content |
row.Spacing(float, Unit) | Horizontal space between items (default 0) |
Note: Width allocation order: ConstantItem widths are reserved first, then AutoItem widths are measured, and the remaining space is split among RelativeItem weights.
Padding
Padding inserts space between a container's edge and its content. Calls are cumulative — chaining .Padding(10).Padding(5) results in 15pt on all sides.
// All sides
col.Item().Padding(20).Text("20pt padding all around");
// Axis-specific
col.Item().PaddingHorizontal(30).PaddingVertical(10).Text("30 left/right, 10 top/bottom");
// Individual sides
col.Item()
.PaddingTop(15)
.PaddingBottom(5)
.PaddingLeft(20)
.PaddingRight(20)
.Text("Per-side padding");
| Method | Sides affected |
|---|---|
Padding(float, Unit) | All four sides |
PaddingHorizontal(float, Unit) | Left + Right |
PaddingVertical(float, Unit) | Top + Bottom |
PaddingTop(float, Unit) | Top only |
PaddingBottom(float, Unit) | Bottom only |
PaddingLeft(float, Unit) | Left only |
PaddingRight(float, Unit) | Right only |
Alignment
Alignment positions content within the available space. Horizontal and vertical alignment can be combined by chaining.
// Horizontal
col.Item().AlignLeft().Text("Left-aligned");
col.Item().AlignCenter().Text("Centered");
col.Item().AlignRight().Text("Right-aligned");
// Vertical
col.Item().Height(100).AlignTop().Text("Top");
col.Item().Height(100).AlignMiddle().Text("Middle");
col.Item().Height(100).AlignBottom().Text("Bottom");
// Combined
col.Item().Height(200).AlignCenter().AlignMiddle()
.Text("Centered both axes");
Size Constraints
Constrain the width and/or height of any element. Constraints are enforced during the layout engine's measure pass.
col.Item().Width(200).Height(100).Background(Color.LightGrey).Text("Fixed 200x100pt");
col.Item().MinWidth(100).MaxWidth(300).Text("Between 100 and 300pt wide");
col.Item().MinHeight(50).Text("At least 50pt tall");
col.Item().MaxHeight(200).Text("No taller than 200pt");
| Method | Description |
|---|---|
Width(float, Unit) | Exact width (sets both min and max) |
Height(float, Unit) | Exact height (sets both min and max) |
MinWidth(float, Unit) | Minimum width constraint |
MaxWidth(float, Unit) | Maximum width constraint |
MinHeight(float, Unit) | Minimum height constraint |
MaxHeight(float, Unit) | Maximum height constraint |
Extend and Shrink
Extend expands the child to fill all available space. Shrink does the opposite — the container wraps tightly around its child.
// Fill both axes
col.Item().Extend().Background(Color.LightGrey).Text("Fills available space");
// Fill one axis only
col.Item().ExtendHorizontal().Text("Full width, natural height");
col.Item().ExtendVertical().Text("Natural width, full height");
// Shrink (container matches child size)
col.Item().Shrink().Background(Color.Yellow).Text("Tight fit");
col.Item().ShrinkHorizontal().Text("Width = content width");
col.Item().ShrinkVertical().Text("Height = content height");
Scale, ScaleToFit, and Flip
Scale transforms the visual rendering of content. ScaleToFit automatically shrinks oversized content to fit the available area.
// Uniform scale (1.5x larger)
col.Item().Scale(1.5f).Text("150% size");
// Axis-specific scale
col.Item().ScaleHorizontal(2f).Text("Stretched horizontally");
// Fit oversized content into available space
col.Item().MaxWidth(200).ScaleToFit().Width(400).Text("This 400pt text fits in 200pt");
// Flip
col.Item().FlipHorizontal().Text("Mirrored");
col.Item().FlipVertical().Text("Flipped upside down");
col.Item().FlipOver().Text("Rotated 180 degrees");
Rotate
FolioPDF supports both 90-degree incremental rotation (affects layout) and arbitrary-angle rotation (visual only, does not change the element's layout footprint).
// 90-degree rotations (layout-aware)
col.Item().RotateRight().Text("90 degrees clockwise");
col.Item().RotateLeft().Text("90 degrees counter-clockwise");
// Arbitrary angle (visual only)
col.Item().Rotate(45).Text("Rotated 45 degrees");
Translate
Offset content from its natural position. Translation is visual only and does not affect the element's layout footprint.
col.Item().TranslateX(20).Text("Shifted 20pt right");
col.Item().TranslateY(-10).Text("Shifted 10pt up");
col.Item().TranslateX(10, Unit.Millimetre).Text("Shifted 10mm right");
Container
A neutral wrapper that contributes nothing to layout. Useful for delegation to helper methods or conditional composition.
col.Item().Container().Text("Same as without Container");
// Delegation pattern
col.Item().Element(container =>
{
container.Padding(10).Background(Color.Yellow).Text("Built by delegate");
});
Paging Controls
Fine-tune how elements interact with page boundaries.
// Force a page break
col.Item().PageBreak();
// Render content only on the first page
col.Item().ShowOnce().Text("Appears on page 1 only");
// Skip the first page, render on all subsequent pages
col.Item().SkipOnce().Text("Appears from page 2 onward");
// Ensure content fits on a single page (moves to next page if it doesn't fit)
col.Item().ShowEntire().Column(inner => { /* ... */ });
// Require minimum vertical space before rendering
col.Item().EnsureSpace(150).Text("At least 150pt of space available");
// Try to keep content together (soft constraint)
col.Item().PreventPageBreak().Column(inner => { /* ... */ });
// Only render on first page, silently discard overflow
col.Item().StopPaging().Text("Never paginates");
| Element | Behavior |
|---|---|
PageBreak() | Forces content after this point to the next page |
ShowOnce() | Renders content once, becomes empty on subsequent pages |
SkipOnce() | Empty on first page, renders on subsequent pages |
ShowEntire() | Requires content to fit on a single page |
EnsureSpace(float) | Moves to next page if minimum space is not available |
PreventPageBreak() | Attempts to keep content on one page (best effort) |
StopPaging() | Renders only on first page, discards overflow |
Layers
Stack multiple elements on top of each other. Exactly one layer must be the PrimaryLayer — it controls the overall size. Other layers stretch to fill that size.
col.Item().Height(200).Layers(layers =>
{
// Background layer (behind primary)
layers.Layer().Extend().Background(Color.FromHex("#E8F0FE"));
// Primary layer (determines size)
layers.PrimaryLayer().Padding(20).Text("Content on top of background");
// Foreground layer (in front of primary)
layers.Layer().AlignRight().AlignBottom()
.Padding(5).Text("Watermark").FontSize(8).FontColor(Color.Grey);
});
Decoration
Splits an area into three vertical sections: Before (header), Content, and After (footer). The Before and After sections repeat on every page while the Content section paginates.
col.Item().Decoration(dec =>
{
dec.Before().Background(Color.FromHex("#333"))
.Padding(10).Text("Section Header").FontColor(Color.White).Bold();
dec.Content().Column(inner =>
{
inner.Spacing(5);
for (int i = 0; i < 100; i++)
inner.Item().Text($"Item {i + 1}");
});
dec.After().BorderTop(1, Color.Grey)
.PaddingTop(5).Text("Section Footer").FontSize(8);
});
Tip: dec.Header() and dec.Footer() are aliases for dec.Before() and dec.After() respectively. Use whichever reads better in context.
Inlined (Wrap-Flow Layout)
Arranges items in a horizontal flow that wraps to the next line when the available width is exhausted — like words in a paragraph.
col.Item().Inlined(inl =>
{
inl.Spacing(8);
inl.AlignCenter();
inl.BaselineMiddle();
foreach (var tag in new[] { "C#", ".NET", "PDF", "Skia", "Layout", "Typography" })
{
inl.Item()
.Background(Color.FromHex("#E0E0E0"))
.CornerRadius(4)
.Padding(6)
.Text(tag).FontSize(10);
}
});
| Method | Description |
|---|---|
Spacing(float) | Sets both horizontal and vertical spacing |
HorizontalSpacing(float) | Space between items on the same line |
VerticalSpacing(float) | Space between lines |
AlignLeft/Center/Right() | Horizontal alignment of items within each line |
AlignJustify() | Stretch to fill line width (last line left-aligned) |
AlignSpaceAround() | Equal space around each item |
BaselineTop/Middle/Bottom() | Vertical alignment within each line strip |
MultiColumn
Flows content across newspaper-style columns. Content fills the first column, then wraps to the next, paginating as needed.
col.Item().MultiColumn(mc =>
{
mc.Columns(3);
mc.Spacing(20);
mc.BalanceHeight();
mc.Content().Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
"Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris...");
// Optional: draw a vertical rule between columns
mc.Spacer().LineVertical(0.5f).LineColor(Color.Grey);
});
Placeholder and DebugArea
Use these during prototyping to visualize layout structure before wiring real content.
// Placeholder: grey hatched rectangle
col.Item().Width(200).Height(100).Placeholder("Logo goes here");
// DebugArea: colored border with label
col.Item().DebugArea("Header Zone", Color.Blue)
.Text("Content inside debug area");
Conditional Rendering
Use ShowIf to conditionally include or exclude content at compose time.
bool isConfidential = true;
col.Item().ShowIf(isConfidential)
.Background(Color.FromRGBA(255, 0, 0, 20))
.Padding(10)
.Text("CONFIDENTIAL").Bold().FontColor(Color.Red);
Navigation
Create internal document links with Sections and SectionLinks, or external links with Hyperlinks.
// Define a named section
col.Item().Section("chapter-1").Text("Chapter 1: Introduction").FontSize(18).Bold();
// Link to a section (clickable in PDF viewers)
col.Item().SectionLink("chapter-1").Text("Go to Chapter 1").Underline().FontColor(Color.Blue);
// External hyperlink
col.Item().Hyperlink("https://truespar.com").Text("Visit TrueSpar").Underline().FontColor(Color.Blue);