Elements

Text

The most fundamental element. Add text with optional styling:

c.Text("Hello, World!")
c.Text("Styled text", template.FontSize(18), template.Bold())
c.Text("Red centered", template.TextColor(pdf.Red), template.AlignCenter())

Text Options

OptionDescription
FontSize(size)Font size in points (default: 12)
Bold()Bold weight
Italic()Italic style
FontFamily(name)Use a registered font
TextColor(color)Foreground color
BgColor(color)Background color
AlignLeft()Left alignment (default)
AlignCenter()Center alignment
AlignRight()Right alignment
Underline()Underline decoration
Strikethrough()Strikethrough decoration
LetterSpacing(pts)Extra space between characters
TextIndent(value)First-line indent

Rich Text

Mixed-style inline text using RichText():

c.RichText(func(rt *template.RichTextBuilder) {
    rt.Span("Normal text ")
    rt.Span("bold", template.Bold())
    rt.Span(" and ")
    rt.Span("red", template.TextColor(pdf.Red))
    rt.Span(" in one line.")
})
┌─────────────────────────────────────────────┐
│  Normal text bold and red in one line.      │
│              ^^^^     ^^^                   │
│              bold     red color             │
└─────────────────────────────────────────────┘

Table

Tables with headers and data rows:

// Basic table
c.Table(
    []string{"Name", "Age", "City"},
    [][]string{
        {"Alice", "30", "Tokyo"},
        {"Bob", "25", "New York"},
        {"Charlie", "35", "London"},
    },
)
┌──────────┬──────┬──────────┐
│  Name    │ Age  │  City    │ ← header (bold)
├──────────┼──────┼──────────┤
│  Alice   │  30  │  Tokyo   │
│  Bob     │  25  │  New York│
│  Charlie │  35  │  London  │
└──────────┴──────┴──────────┘

Styled Table

darkBlue := pdf.RGBHex(0x1A237E)
lightGray := pdf.RGBHex(0xF5F5F5)

c.Table(
    []string{"Product", "Category", "Qty", "Unit Price", "Total"},
    [][]string{
        {"Laptop Pro 15", "Electronics", "2", "$1,299.00", "$2,598.00"},
        {"Wireless Mouse", "Accessories", "10", "$29.99", "$299.90"},
        {"USB-C Hub", "Accessories", "5", "$49.99", "$249.95"},
        {"Monitor 27\"", "Electronics", "3", "$399.00", "$1,197.00"},
        {"Keyboard", "Accessories", "10", "$79.99", "$799.90"},
        {"Webcam HD", "Electronics", "4", "$89.99", "$359.96"},
    },
    template.ColumnWidths(30, 20, 10, 20, 20),
    template.TableHeaderStyle(
        template.TextColor(pdf.White),
        template.BgColor(darkBlue),
    ),
    template.TableStripe(lightGray),
)
┌─────────────┬────────────┬─────┬───────────┬──────────┐
│  Product    │  Category  │ Qty │Unit Price │  Total   │ ← white on dark blue
├─────────────┼────────────┼─────┼───────────┼──────────┤
│  Laptop Pro │ Electronics│  2  │ $1,299.00 │$2,598.00 │ ← white bg
│  Wireless.. │ Accessories│ 10  │    $29.99 │  $299.90 │ ← gray stripe
│  USB-C Hub  │ Accessories│  5  │    $49.99 │  $249.95 │ ← white bg
│  Monitor 27"│ Electronics│  3  │   $399.00 │$1,197.00 │ ← gray stripe
│  Keyboard   │ Accessories│ 10  │    $79.99 │  $799.90 │ ← white bg
│  Webcam HD  │ Electronics│  4  │    $89.99 │  $359.96 │ ← gray stripe
└─────────────┴────────────┴─────┴───────────┴──────────┘

Table Options

OptionDescription
ColumnWidths(widths...)Column width percentages (must sum to 100)
ColumnAlign(aligns...) Since v1.0.10 Per-column horizontal alignment: AlignLeft, AlignCenter, AlignRight (applies to header + body)
TableHeaderStyle(opts...)Style for header row
TableStripe(color)Alternating row background color
TableCellVAlign(align)Vertical alignment: VAlignTop, VAlignMiddle, VAlignBottom
WithTableBorder(spec)Outer border around the table
WithTableCellBorder(spec)Same border drawn around every header + body cell (Excel-style grid)
WithTableBorderCollapse(b)Collapse adjacent cell borders
WithTableBackground(color)Fill the table's outer box

Borders & Backgrounds

Since v1.0.7

Add an outer frame, per-cell grid lines, or a backdrop fill. Build a BorderSpec with template.Border(...) and apply it via WithTableBorder (outer) or WithTableCellBorder (every header + body cell):

outer := template.Border(
    template.BorderWidth(document.Pt(1)),
    template.BorderColor(pdf.RGBHex(0x1A237E)),
)
grid := template.Border(
    template.BorderWidth(document.Pt(0.5)),
    template.BorderColor(pdf.Gray(0.5)),
)

// Outer frame only
c.Table(header, rows, template.WithTableBorder(outer))

// Excel-style grid lines on every cell
c.Table(header, rows, template.WithTableCellBorder(grid))

// Outer frame + grid + background fill
c.Table(header, rows,
    template.WithTableBorder(outer),
    template.WithTableCellBorder(grid),
    template.WithTableBackground(pdf.RGBHex(0xFAFAFA)),
)

// Dashed cell grid
dashed := template.Border(
    template.BorderWidth(document.Pt(0.75)),
    template.BorderColor(pdf.RGBHex(0x0D47A1)),
    template.BorderLine(document.BorderDashed),
)
c.Table(header, rows, template.WithTableCellBorder(dashed))

See Borders for the full BorderSpec builder reference.

Table Vertical Alignment

c.Table(
    []string{"Align", "Short", "Long Content"},
    [][]string{
        {"Top", "A", "This is a longer text that wraps to multiple lines"},
        {"Middle", "B", "Another longer text for demonstration purposes"},
    },
    template.TableCellVAlign(document.VAlignMiddle),
)

Table Column Alignment

Since v1.0.10

Set horizontal alignment per column — typical use case is right-aligning numeric or currency columns. Each argument applies to the column at the same index, in both the header and body rows. Columns without a provided alignment fall back to the default left alignment.

c.Table(
    []string{"Item", "Qty", "Price"},
    [][]string{
        {"Apple",  "3",   "$1.50"},
        {"Banana", "12",  "$0.30"},
        {"Cherry", "120", "$5.00"},
    },
    template.ColumnAlign(
        document.AlignLeft,   // Item
        document.AlignRight,  // Qty
        document.AlignRight,  // Price
    ),
)

Image

Add JPEG or PNG images:

imgData, _ := os.ReadFile("photo.jpg")

c.Image(imgData)
c.Image(imgData, template.FitWidth(document.Mm(80)))
c.Image(imgData, template.FitHeight(document.Mm(50)))

Image Options

OptionDescription
FitWidth(value)Scale to specified width
FitHeight(value)Scale to specified height
WithFitMode(mode)Fit mode: FitContain, FitCover, FitStretch, FitOriginal
WithAlign(align)Horizontal alignment: AlignLeft, AlignCenter, AlignRight
MinDisplayWidth(v)Overflow to next page if shrunk below this width
MinDisplayHeight(v)Overflow to next page if shrunk below this height
WithImageBorder(spec)Border around the image
WithImageBackground(color)Fill the image's box (useful for transparent PNGs)

Image Fit Modes

// Contain: scale to fit, preserve aspect ratio (default)
c.Image(data, template.WithFitMode(document.FitContain))

// Cover: scale to fill, may crop
c.Image(data, template.WithFitMode(document.FitCover))

// Stretch: fill bounds, may distort
c.Image(data, template.WithFitMode(document.FitStretch))

// Original: use original dimensions
c.Image(data, template.WithFitMode(document.FitOriginal))

Image Alignment

c.Image(data, template.FitWidth(document.Mm(40)), template.WithAlign(document.AlignCenter))
c.Image(data, template.FitWidth(document.Mm(40)), template.WithAlign(document.AlignRight))

Border & Background

Since v1.0.7

Frame an image and fill its box (handy for transparent PNGs):

c.Image(pngData,
    template.FitWidth(document.Mm(60)),
    template.WithImageBorder(template.Border(
        template.BorderWidth(document.Pt(2)),
        template.BorderColor(pdf.RGBHex(0xE53935)),
    )),
    template.WithImageBackground(pdf.RGBHex(0xFFF8E1)),
)

See Borders for the full BorderSpec builder reference.

Box

Since v1.0.7

Wrap arbitrary column content in a styled rectangular container with a border, fill, and padding. Useful for callouts, notice boxes, or grouping related elements:

c.Box(func(c *template.ColBuilder) {
    c.Text("Inside a box", template.Bold())
    c.Text("with two lines of body copy.")
},
    template.WithBoxBorder(template.Border(
        template.BorderWidth(document.Pt(1)),
        template.BorderColor(pdf.RGBHex(0x1A237E)),
    )),
    template.WithBoxBackground(pdf.RGBHex(0xE8EAF6)),
    template.WithBoxPadding(document.UniformEdges(document.Mm(4))),
)

Box Options

OptionDescription
WithBoxBorder(spec)Border around the box
WithBoxBackground(color)Fill color
WithBoxPadding(edges)Inner spacing
WithBoxMargin(edges)Outer spacing
WithBoxWidth(value)Explicit width
WithBoxHeight(value)Explicit height

Borders

Since v1.0.7

template.Border(...) builds a reusable BorderSpec that can be applied to tables (WithTableBorder / WithTableCellBorder), images (WithImageBorder), boxes (WithBoxBorder), and text (WithTextBorder):

spec := template.Border(
    template.BorderWidth(document.Pt(1)),       // uniform edges
    template.BorderColor(pdf.RGBHex(0x1A237E)),
    template.BorderLine(document.BorderSolid),  // BorderSolid | BorderDashed | BorderDotted
)

The default is 1pt black solid when no width is specified.

Border Helpers

OptionDescription
Border(opts...)Build a BorderSpec
BorderWidth(v)Uniform width on all four edges
BorderWidths(t, r, b, l)Per-edge widths in CSS order: top, right, bottom, left
BorderColor(c)Edge color
BorderLine(style)Line style: BorderSolid, BorderDashed, BorderDotted, BorderNone

List

Unordered List

c.List([]string{
    "Declarative document definition",
    "All element types supported",
    "Style options (bold, italic, color, align)",
    "Header and footer support",
})
┌─────────────────────────────────────────────┐
│  • Declarative document definition          │
│  • All element types supported              │
│  • Style options (bold, italic, color, ...)  │
│  • Header and footer support                │
└─────────────────────────────────────────────┘

Ordered List

c.OrderedList([]string{
    "Text with styles",
    "Tables with headers",
    "Lists (ordered/unordered)",
    "Lines and spacers",
    "QR codes and barcodes",
})
┌─────────────────────────────────────────────┐
│  1. Text with styles                        │
│  2. Tables with headers                     │
│  3. Lists (ordered/unordered)               │
│  4. Lines and spacers                       │
│  5. QR codes and barcodes                   │
└─────────────────────────────────────────────┘

List Options

OptionDescription
ListIndent(value)Indentation from left

Line

Horizontal rules with optional color and thickness:

// Default line (gray, 1pt)
c.Line()

// Colored line
c.Line(template.LineColor(pdf.Red))
c.Line(template.LineColor(pdf.Blue))

// Custom thickness
c.Line(template.LineThickness(document.Pt(0.5)))   // thin
c.Line(template.LineThickness(document.Pt(2)))     // medium
c.Line(template.LineThickness(document.Pt(5)))     // thick

// Color + thickness
c.Line(
    template.LineColor(pdf.RGBHex(0x1A237E)),
    template.LineThickness(document.Pt(2)),
)
┌─────────────────────────────────────────────┐
│  Default line:                              │
│  ─────────────────────────────── (gray 1pt) │
│  Red line:                                  │
│  ─────────────────────────────── (red)      │
│  Thin (0.5pt):                              │
│  ─────────────────────────────── (thin)     │
│  Thick (5pt):                               │
│  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ (thick)    │
└─────────────────────────────────────────────┘

Line Options

OptionDescription
LineColor(color)Line color
LineThickness(value)Line thickness

Spacer

Add vertical space between elements:

c.Text("Before spacer")
c.Spacer(document.Mm(10))    // 10mm gap
c.Text("After spacer")

c.Spacer(document.Mm(5))     // 5mm
c.Spacer(document.Mm(15))    // 15mm
c.Spacer(document.Mm(30))    // 30mm
┌─────────────────────────────────────────────┐
│  Before spacer                              │
│                                             │
│                  ↕ 10mm                     │
│                                             │
│  After spacer                               │
└─────────────────────────────────────────────┘

QR Code

Generate QR codes from text or URLs:

// Basic QR code
c.QRCode("https://gpdf.dev")

// With custom size
c.QRCode("https://gpdf.dev", template.QRSize(document.Mm(30)))

// With error correction level
c.QRCode("HELLO", template.QRSize(document.Mm(25)),
    template.QRErrorCorrection(qrcode.LevelH))

// Japanese content
c.QRCode("こんにちは世界", template.QRSize(document.Mm(30)))

QR Codes with Different Sizes

page.AutoRow(func(r *template.RowBuilder) {
    r.Col(4, func(c *template.ColBuilder) {
        c.Text("20mm", template.FontSize(9))
        c.QRCode("https://gpdf.dev", template.QRSize(document.Mm(20)))
    })
    r.Col(4, func(c *template.ColBuilder) {
        c.Text("30mm", template.FontSize(9))
        c.QRCode("https://gpdf.dev", template.QRSize(document.Mm(30)))
    })
    r.Col(4, func(c *template.ColBuilder) {
        c.Text("40mm", template.FontSize(9))
        c.QRCode("https://gpdf.dev", template.QRSize(document.Mm(40)))
    })
})
┌───────────────┬───────────────┬───────────────┐
│  20mm         │  30mm         │  40mm         │
│  ┌──┐         │  ┌────┐       │  ┌──────┐     │
│  │QR│         │  │ QR │       │  │  QR  │     │
│  └──┘         │  └────┘       │  │      │     │
│               │               │  └──────┘     │
└───────────────┴───────────────┴───────────────┘

Error Correction Levels

LevelRecoveryBest For
qrcode.LevelL~7%Clean environments
qrcode.LevelM~15%General use (default)
qrcode.LevelQ~25%Industrial use
qrcode.LevelH~30%Harsh environments
import "github.com/gpdf-dev/gpdf/qrcode"

c.QRCode("HELLO", template.QRErrorCorrection(qrcode.LevelH))

QR Code Options

OptionDescription
QRSize(value)Display size (width = height)
QRMinSize(value)Minimum display size — overflow to next page instead of shrinking below
QRErrorCorrection(level)Error correction level
QRScale(s)Pixels per QR module

Minimum Size

Since v1.0.6

QRMinSize prevents the layout from shrinking a QR code below a configured minimum. When the remaining space on the current page would force the QR below that size, it overflows to the next page instead of rendering at an unscannable size.

c.QRCode("https://gpdf.dev",
    template.QRSize(document.Mm(30)),
    template.QRMinSize(document.Mm(20)))

Barcode

Generate Code 128 barcodes:

// Basic barcode
c.Barcode("INV-2026-0001")

// With custom width
c.Barcode("PRODUCT-A-12345", template.BarcodeWidth(document.Mm(80)))

// With custom height
c.Barcode("SMALL-BAR", template.BarcodeHeight(document.Mm(10)))

// Numeric data (automatically optimized with Code C)
c.Barcode("1234567890")

Barcodes in Columns

page.AutoRow(func(r *template.RowBuilder) {
    r.Col(6, func(c *template.ColBuilder) {
        c.Text("Item A", template.FontSize(9))
        c.Barcode("ITEM-A-001", template.BarcodeWidth(document.Mm(60)))
    })
    r.Col(6, func(c *template.ColBuilder) {
        c.Text("Item B", template.FontSize(9))
        c.Barcode("ITEM-B-002", template.BarcodeWidth(document.Mm(60)))
    })
})
┌────────────────────────┬────────────────────────┐
│  Item A                │  Item B                │
│  ║║│║║│║║║│║║│║║│      │  ║║│║║│║║║│║║│║║│      │
│  ITEM-A-001            │  ITEM-B-002            │
└────────────────────────┴────────────────────────┘

Barcode Options

OptionDescription
BarcodeWidth(value)Display width
BarcodeHeight(value)Display height
BarcodeFormat(format)Barcode format (default: Code 128)

Absolute Positioning

Place elements at exact XY coordinates on the page, outside the normal grid flow. Useful for watermarks, stamps, logos, and overlays.

page.Absolute(document.Mm(120), document.Mm(20), func(c *template.ColBuilder) {
    c.Text("CONFIDENTIAL", template.FontSize(20), template.Bold(), template.TextColor(pdf.Red))
})

// With explicit size
page.Absolute(document.Mm(10), document.Mm(250), func(c *template.ColBuilder) {
    c.QRCode("https://gpdf.dev", template.QRSize(document.Mm(20)))
}, gpdf.AbsoluteWidth(document.Mm(25)), gpdf.AbsoluteHeight(document.Mm(25)))

// Use page corner as origin (ignores margins)
page.Absolute(document.Mm(0), document.Mm(0), func(c *template.ColBuilder) {
    c.Text("Top-left corner of page")
}, gpdf.AbsoluteOriginPage())
┌─ Page ──────────────────────────────────────────┐
│  ┌─ Content Area ───────────────────────────┐   │
│  │                                          │   │
│  │   [Normal flow content]                  │   │
│  │                                          │   │
│  │              ┌──────────────┐            │   │
│  │              │ CONFIDENTIAL │ ← absolute │   │
│  │              └──────────────┘   (120,20) │   │
│  │                                          │   │
│  │   ┌──┐                                   │   │
│  │   │QR│ ← absolute (10,250)               │   │
│  │   └──┘                                   │   │
│  └──────────────────────────────────────────┘   │
└─────────────────────────────────────────────────┘

Coordinate Origins

OriginDescriptionDefault
Content AreaXY relative to top-left of content area (inside margins)Yes
PageXY relative to top-left corner of the page (ignores margins)No

Absolute Positioning Options

OptionDescription
AbsoluteWidth(value)Explicit width for the absolute block
AbsoluteHeight(value)Explicit height for the absolute block
AbsoluteOriginPage()Use page corner as origin instead of content area

Page Number / Total Pages

Automatic page numbering in headers or footers:

// Current page number (e.g., "1", "2", "3")
c.PageNumber(template.AlignRight(), template.FontSize(8))

// Total page count (e.g., "4 total pages")
c.TotalPages(template.AlignRight(), template.FontSize(9))

Both accept standard text options for styling.