Skip to content

Columns

Dragon edited this page Jun 4, 2026 · 1 revision

Multi-column layout

Page::columns() runs a scoped block in which flowing text fills several equal-width columns. Inside the block, cell() and markdown() wrap to the current column width and fill each column top-to-bottom before moving to the next column, then to a new page (sequential fill). Outside the block, layout is unchanged (full content width).

use DragonOfMercy\PhpPdf\Document;
use DragonOfMercy\PhpPdf\Font;
use DragonOfMercy\PhpPdf\Page;

$doc = new Document();
$page = $doc->addPage();
$page->setFont(Font::helvetica(), 11);

$page->columns(2, gap: 8, render: function (Page $p): void {
    $p->markdown($longArticle);
    // fills column 0 to the bottom margin, then column 1,
    // then continues on a new page at column 0
});

$page->cell(w: 100, text: 'Back to full width here.');

Signature

$page->columns(
    int $count,
    float $gap = 0.0,
    ColumnFill $fill = ColumnFill::SEQUENTIAL,
    ?callable $render = null,
): self
Parameter Description
count Number of equal-width columns (>= 1).
gap Horizontal space between columns, in the document unit (>= 0).
fill ColumnFill::SEQUENTIAL (default). ColumnFill::BALANCED is reserved and throws until implemented.
render Callback function (Page $p): void that draws the column content. It receives the page currently being drawn on.

Column width is derived automatically: columnWidth = (contentWidth - (count - 1) * gap) / count, where contentWidth is the page width minus the left and right margins.

Behavior

  • Sequential fill. A column is filled to the bottom margin, then flow continues at the top of the next column; after the last column, a new page is added and flow resumes at column 0. This happens regardless of setAutoPageBreak() - opening a columns() block is itself the signal to flow.
  • Default geometry inside the block. cell() and markdown() with no explicit x start at the current column's left edge; with no explicit width they use the column width, so wrapping happens at the column width.
  • After the block. Full-width flow resumes and the cursor is placed below the lowest column content on the final page.

columnBreak()

Forces flow to continue at the top of the next column (or a new page's first column when already in the last column). Only valid inside a columns() block; throws otherwise.

$page->columns(2, gap: 8, render: function (Page $p): void {
    $p->markdown($intro);
    $p->columnBreak();        // start the next column now
    $p->markdown($sidebar);
});

Limitations (this version)

  • ColumnFill::BALANCED (equal-height columns) is not yet implemented.
  • Columns are equal width; per-column widths are not configurable.
  • image(), barcode(), and table() are not supported inside a columns() block and throw; call them outside the block.
  • columns() blocks cannot be nested.

See also: Cells, Markdown.

Clone this wiki locally