Three Ways to Write a Table in Podlite

oalders2 pts0 comments

Three ways to write a table in Podlite

MORE:

Toggle navigation

Perl.com

ABOUT

AUTHORS

CATEGORIES

TAGS

Three ways to write a table in Podlite

Jul 15, 2026 by

Aliaksandr Zahatski

In my previous article I introduced Podlite as a block-based markup language. Today I’ll zoom into one piece: tables.

I write tables in three rough shapes: a few rows of words I’m jotting down, a visual grid like a tic-tac-toe board, or a data export I want to embed in a document. Podlite has three syntaxes around the same model, one per shape. The first has several flavors, so let’s start with that.

One model, three syntaxes

The first syntax is text-mode. It’s flexible. The simplest version is =table followed by rows. Pipes for separators:

=table<br>mouse | mice<br>horse | horses<br>elephant | elephants

Plus signs work too, and you can leave cells empty:

=table<br>X | O |<br>---+---+---<br>| X | O<br>---+---+---<br>| | X

That renders as a tic-tac-toe board. Three rows of three cells, same table model as anything else.

When you want a header and a caption, use the delimited form. Add :caption(...) and put a ===== row under the head:

=begin table :caption('Critters')<br>Animal Legs Eats<br>Zebra 4 Cookies<br>Human 2 Pizza<br>Shark 0 Fish<br>=end table

The parser handles whitespace, pipes, or plus signs as column boundaries. A ===== line marks the previous row as a header. I reach for this form first when I&rsquo;m typing into a notebook. It stays readable as I edit, and it survives copy-paste from a terminal.

The second syntax is structured. Use it when you need cell spans, semantic markup, or rich content in cells. Each row and each cell becomes its own block. The ===== line becomes a :header attribute on the row:

=begin table :caption('My coffee morning')

=begin row :header<br>=cell Step<br>=cell Tool<br>=cell Time<br>=end row

=begin row<br>=cell Grind<br>=cell Burr grinder<br>=cell 20s<br>=end row

=begin row<br>=cell Brew<br>=for cell :colspan(2)<br>Aeropress, 90 seconds with bloom<br>=end row

=end table

A cell can hold any Podlite block: a paragraph, a code block, a picture, an embedded diagram. This call was made early in the spec: tables in Podlite are not a visual feature, they are containers that render as a grid.

The third syntax is data-driven. If the numbers are short enough to live in the document, put them directly inside a =data-table block:

=begin data-table :caption('Build status') :mime-type<br>component,status<br>parser,green<br>renderer,green<br>playground,yellow<br>=end data-table

Some data has its own life: a CSV export, a TSV log, anything that exists before the document does. Keep it in a separate =data block and reference it via :src. If the data starts with column labels, mark them with the header=present parameter from RFC 4180 §3:

=for data-table :src :caption('Walks this month')

=begin data :key :mime-type<br>date distance note<br>2026-04-12 5km morning fog<br>2026-04-15 3km park loop<br>2026-04-22 8km coastal trail<br>=end data

The =data block holds raw TSV: tab-split, no quoting, which is what most TSV tools emit. Tools that walk the document read the structured data directly, and readers see the rendered table from the same source.

When tables break

Tables break in real documents. A copy-paste loses a column, two rows pick different separators, a CSV cell holds an unmatched quote. The Podlite spec defines four rules so the parser warns you instead of silently corrupting the document:

Per-line separator detection. Each row decides its separator from what it sees.

Cell count validation. Short rows pad with empty cells, long rows truncate. Both produce a warning.

Mixed-separator warning. Pipes in the header and whitespace in data still work, but you get a warning.

CSV recovery. Missing data renders an empty table. A non-CSV MIME type falls back to a =code block so the content stays visible.

I&rsquo;d rather see a warning in the console than ship a document with a dropped row.

Try it

Paste any of these examples into pod6.in. The playground renders Podlite live, no install needed. The full table grammar lives in the Podlite specification.

If you build something with this, or hit a case the spec does not cover, open a discussion at podlite-specs.

Thanks for reading,

Alex

Tags

tooling

documentation

pod

podlite

syntax

Aliaksandr Zahatski

A passionate open-source developer focused on personal publishing, decentralized systems, and software engineering. Co-author and maintainer of Podlite, a modern markup language for organizing knowledge, technical documentation, and publishing.

Browse their articles

Feedback

Something wrong with this article? Help us out by opening an issue or pull request on GitHub

TPRF Gold Sponsor

TPRF Silver Sponsor

TPRF Bronze Sponsor

TPRF Bronze Sponsor

TPRF Bronze Sponsor

TPRF Bronze Sponsor

PERL ADS

Perl Resources

Get Perl

Learn About Perl

Get Perl Code

Help Perl

Site Map

Home

About

Authors

Categories

Tags

Contact Us

To get in touch, submit an issue to perladvent/perldotcom on...

table data podlite cell three block

Related Articles