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");
});
MethodDescription
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");
});
MethodDescription
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");
MethodSides 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");
MethodDescription
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");
ElementBehavior
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);
    }
});
MethodDescription
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);