Skip to content

Pandoc Markdown Tables: Captions, Grid Tables and Column Widths

By MarkdownTables.com editorial teamUpdated

On this page

How do I add a caption to a table in Pandoc?

GitHub Flavored Markdown has no table captions, but Pandoc's table_captions extension (on by default in -f markdown) does. The caption is a normal paragraph that begins with Table: or a bare :, placed directly before or after the table with a blank line in between. Inline Markdown such as *emphasis* works in it, and it can wrap over several lines.

A pipe table with a Pandoc caption
Markdown
| Planet  | Moons | Day length |
|:--------|------:|-----------:|
| Mercury |     0 |   4,223 h  |
| Earth   |     1 |      24 h  |
| Mars    |     2 |    24.7 h  |

Table: Planets of the inner solar system

The preview follows GitHub, which shows the Table: line as an ordinary paragraph. Pandoc renders it as the table's caption.

Open in editor : A pipe table with a Pandoc caption
The same file to three formatsShell
pandoc planets.md -o planets.html
pandoc planets.md -o planets.pdf      # LaTeX: numbered "Table 1: …" caption
pandoc planets.md -o planets.docx     # Word: caption paragraph above the table

In HTML the caption becomes <caption>; in LaTeX/PDF it is numbered (“Table 1:”) and appears in \listoftables; in Word it uses the Table Caption style. To label and cross-reference tables, use Quarto ({#tbl-name}, below) or the pandoc-crossref filter ({#tbl:name}); plain Pandoc leaves the braces in the caption as text. Other caption options across flavors are in headerless tables and captions.

Pandoc’s four table syntaxes compared

All four syntaxes are enabled by default when Pandoc reads markdown. They differ in what a cell can hold and how easy they are to type:

Pandoc table syntaxes
SyntaxExtensionWrapped text in cellsMerged cellsHeaderlessRenders on GitHub
Pipepipe_tablesNo (one line per row)NoNoYes
Simplesimple_tablesNoNoYesNo
Multilinemultiline_tablesYesNoYesNo
Gridgrid_tablesYes, plus lists and code blocksYes (Pandoc 3.0+)YesNo

Pipe tables

The same syntax as GitHub (see Markdown table syntax): a header row, a delimiter row with optional colons for alignment, one line per row. Use pipe tables when the file must also render on GitHub, GitLab or in an editor preview.

Pipe table with left, center and right alignment
Markdown
| Option        | Default | Meaning                    |
|:--------------|:-------:|---------------------------:|
| `--columns`   |   72    | Line length for wrapping   |
| `--wrap`      |  auto   | How text lines are wrapped |
Preview
OptionDefaultMeaning
--columns72Line length for wrapping
--wrapautoHow text lines are wrapped

Simple tables

Columns are defined by a dashed line under the header; alignment comes from where the header text sits relative to the dashes (flush right = right-aligned, centered = centered). Each row is one line.

Simple tablePandoc Markdown
  Right     Left     Center     Default
-------     ------ ----------   -------
     12     12        12            12
    123     123       123          123
      1     1          1             1

Table: Demonstration of simple table syntax.

Leave out the header, and close the table with a second dashed line, to get a headerless table:

Headerless simple tablePandoc Markdown
-------     ------ ----------   -------
     12     12        12            12
    123     123       123          123
-------     ------ ----------   -------

Multiline tables

Multiline tables start and end with a full-width dashed line, and rows are separated by blank lines, so a cell can wrap over several source lines. The width of each column's dashes sets its relative width in the output.

Multiline table (from the Pandoc manual)Pandoc Markdown
-------------------------------------------------------------
 Centered   Default           Right Left
  Header    Aligned         Aligned Aligned
----------- ------- --------------- -------------------------
   First    row                12.0 Example of a row that
                                    spans multiple lines.

  Second    row                 5.0 Here's another one. Note
                                    the blank line between
                                    rows.
-------------------------------------------------------------

Table: Here's the caption. It, too, may span
multiple lines.

Grid tables: merged cells and block content

Grid tables draw every cell with +, - and |. A row of = separates the header, and colons in that row set alignment. Cells hold any block content: paragraphs, lists, code blocks. Since Pandoc 3.0, leaving out a border creates a merged cell: no | between two cells spans columns, and no +---+ line between rows spans rows.

Grid table with a column span and a row spanPandoc Markdown
: Temperature extremes, 1961–1990.

+---------------------+----------+
| Property            | Earth    |
+=============+=======+==========+
|             | min   | -89.2 °C |
| Temperature +-------+----------+
| 1961-1990   | mean  | 14 °C    |
|             +-------+----------+
|             | max   | 56.7 °C  |
+-------------+-------+----------+

Here “Property” spans two columns and “Temperature 1961-1990” spans three rows; Pandoc writes colspan/rowspan in HTML and \multicolumn/\multirow in LaTeX.

Lists and code blocks inside cellsPandoc Markdown
+-----------+------------------------------+
| Step      | Details                      |
+:==========+:=============================+
| Install   | - Download the binary        |
|           | - Add it to `PATH`           |
+-----------+------------------------------+
| Verify    | ```                          |
|           | pandoc --version             |
|           | ```                          |
+-----------+------------------------------+

Pandoc 3 grid tables can also have a footer: rows below a second = separator become <tfoot>.

Grid table with a footer rowPandoc Markdown
+-----------+----------+
| Region    | Revenue  |
+:==========+=========:+
| EMEA      | 1.2M     |
+-----------+----------+
| APAC      | 0.8M     |
+===========+==========+
| Total     | 2.0M     |
+===========+==========+

Grid tables are tedious to type. Write the data as a pipe table and let Pandoc convert it with pandoc in.md -t markdown-pipe_tables-simple_tables-multiline_tables, or use an editor mode that redraws grids (Emacs table.el or org-mode, or a grid-table extension for VS Code).

Column widths and the --columns option

Pandoc decides column widths differently per syntax. For pipe tables, the rule is: if any line of the table source is longer than --columns (default 72), the table takes the full text width and each column gets a share proportional to the number of dashes in its delimiter cell. If every line fits, columns size to their content.

A long row triggers relative widths: 5 dashes vs. 36 dashes
Markdown
| Flag | Description |
|-----:|:------------------------------------|
| `-s` | Produce a standalone document with a header and footer, using the default template for the output format. |
Preview
FlagDescription
-sProduce a standalone document with a header and footer, using the default template for the output format.

In HTML or PDF output, Pandoc gives the first column about 12% and the second about 88% of the width. GitHub ignores the dashes.

Open in editor : A long row triggers relative widths: 5 dashes vs. 36 dashes
How widths are set
SyntaxWidth ruleTo control it
PipeRelative to dashes, only when a line exceeds --columnsAdjust dash counts; raise or lower --columns
SimpleNatural (sized to content)Switch to multiline or grid
MultilineRelative to the column width in the sourceWiden or narrow the dashed columns
GridRelative to the column width in the sourceRedraw the grid
Quartotbl-colwidths overrides the abovetbl-colwidths="[75,25]" after the caption

In LaTeX output, wrapped columns become p{…} columns of a longtable, so long tables break across pages. For finer control in PDF, convert the table once to LaTeX with the Markdown table to LaTeX tool and edit it there.

Converting tables to PDF, DOCX, HTML and GFM

Common conversionsShell
# HTML with a full page around it
pandoc report.md -s -o report.html

# PDF through LaTeX; xelatex or lualatex handle Unicode such as °C and emoji fonts
pandoc report.md -o report.pdf --pdf-engine=xelatex

# Word, styled by your own template's "Table" style
pandoc report.md -o report.docx --reference-doc=custom-reference.docx

# Back to GitHub Markdown (grid/multiline tables become pipe tables where possible)
pandoc report.md -t gfm -o README.md

# Rewrap or normalize tables in Pandoc Markdown
pandoc report.md -t markdown --columns=100 -o report.normalized.md
  • PDF. Pandoc goes through LaTeX by default (pdflatex). The default template loads longtable, booktabs and multirow, so captions, footers and spans work. Use --pdf-engine=xelatex or lualatex when cells contain non-Latin characters.
  • DOCX. Tables get Word's “Table” style. To change borders or shading, edit that style in a reference document (pandoc -o custom-reference.docx --print-default-data-file reference.docx) and pass it with --reference-doc.
  • HTML. Captions become <caption>; relative widths become a <colgroup> with percentage widths. Alignment is written as inline text-align styles.
  • GitHub Markdown. -t gfm writes pipe tables, puts the caption in a paragraph after the table, splits merged cells into empty ones, and writes an HTML <table> when a cell holds a list or code block.

For the reverse direction, pandoc page.html -t gfm turns HTML tables into pipe tables, or use the HTML table to Markdown converter for a single table.

Quarto: tbl-cap, tbl-colwidths and @tbl- references

Quarto runs Pandoc, so all four syntaxes and Table: captions work. It adds labels, numbering and cross-references. Put the caption below the table with a #tbl- label at the end, then refer to it with @tbl-…:

Caption, label, widths and a cross-referenceQuarto Markdown
| Fruit  | Price |
|--------|------:|
| Apple  |  0.50 |
| Mango  |  1.75 |

: Fruit prices {#tbl-fruit tbl-colwidths="[75,25]"}

Prices are listed in @tbl-fruit.

tbl-colwidths takes percentages per column. Set it per table after the caption, for the whole document in YAML, or in a code cell:

Document-level defaultYAML
---
title: "Report"
tbl-colwidths: [60, 40]   # default for every table in the document
---
Caption and label for a generated tableQuarto
```{r}
#| label: tbl-cars
#| tbl-cap: "Stopping distance by speed"
#| tbl-colwidths: [50, 50]
knitr::kable(head(cars))
```

Quarto's docs note that shortcodes don't work inside grid tables and suggest list tables instead when cells need complex content.

Tables from R with knitr::kable

In R Markdown and Quarto, knitr::kable() is the quickest way to turn a data frame into a Markdown table. With format = "pipe" it writes a pipe table with a Table: caption, which Pandoc then converts to any output:

knitr::kableR
knitr::kable(
  head(mtcars[, 1:4]),
  format  = "pipe",
  digits  = 1,
  caption = "Fuel economy and engine size"
)
kable output: caption line plus pipe table
Markdown
Table: Fuel economy and engine size

|                  |  mpg| cyl| disp|  hp|
|:-----------------|----:|---:|----:|---:|
|Mazda RX4         | 21.0|   6|  160| 110|
|Mazda RX4 Wag     | 21.0|   6|  160| 110|
|Datsun 710        | 22.8|   4|  108|  93|

kable writes row names as an unlabeled first column; pass row.names = FALSE to drop them.

Open in editor : kable output: caption line plus pipe table

For the same job in Python, df.to_markdown() is covered in Markdown tables in Python; add the Table: line yourself.

What survives in each output format

Pandoc table features by output format
OutputCaptionColumn widthsLists/code in cellsMerged cells
HTML (-t html)Caption becomes <caption>; widths become <colgroup>.YesYesYesYes
PDF via LaTeXlongtable with booktabs; spans use \multicolumn / \multirow.Yes: NumberedYesYesYes
Word (.docx)Uses the reference doc’s Table and Table Caption styles.YesYesYesYes
GitHub Markdown (-t gfm)Plain tables become pipe tables; complex ones fall back to raw HTML.Partly: Paragraph after the tablePartly: Only in the HTML fallbackPartly: HTML fallbackPartly: Spans lost in pipe output
QuartoPandoc underneath, plus #tbl- labels and tbl-colwidths.Yes: Numbered, cross-referencedYesYesYes

✅ supported · ⚠️ partly or with a workaround · ❌ not supported · Last verified October 2026

Tested against Pandoc 3.6. Merged cells require grid tables; lists and code in cells require grid tables.

Common mistakes and fixes

Padding a grid cell with spaces turns it into code

Grid cells are parsed as Markdown blocks, so four or more leading spaces make an indented code block. Don't right-align numbers by padding; put colons in the = separator row instead.

Broken: 1.2M renders as a code blockPandoc Markdown
+--------+----------+
| Region | Revenue  |
+========+==========+
| EMEA   |     1.2M |
+--------+----------+
Fixed: alignment from the separator rowPandoc Markdown
+--------+----------+
| Region | Revenue  |
+:=======+=========:+
| EMEA   | 1.2M     |
+--------+----------+

Other mistakes

  • Caption ignored. Missing blank line, or the input format is gfm or commonmark, which don't have table_captions. Use -f markdown.
  • Ragged grid lines. Every | and + must line up exactly; one shifted character and the grid becomes a paragraph. Use a monospace editor and a grid-aware mode.
  • Unexpected full-width table. A long pipe-table row exceeded --columns. Shorten it, set --columns=200, or balance the dashes deliberately.
  • Merged cells vanish. Pandoc older than 3.0 reads grid tables without spans; check pandoc --version.
  • Unicode errors in PDF. Switch to --pdf-engine=xelatex.

Generate a pipe table to start from

Frequently asked questions

How do I add a caption to a Markdown table in Pandoc?

Put a paragraph starting with Table: (or just :) directly before or after the table, separated by a blank line: Table: Revenue by region. Pandoc turns it into a real caption in HTML, LaTeX/PDF and Word. It works for pipe, simple, multiline and grid tables.

Can you merge cells in a Pandoc table?

Yes, with grid tables in Pandoc 3.0 and later. Leave out the | or +---+ border between cells to make one cell span columns or rows. Spans are kept in HTML, LaTeX and DOCX output. Pipe, simple and multiline tables have no spans.

How do I set column widths for a Pandoc table?

In pipe tables, widths come from the dashes in the delimiter row, but only when a line is longer than --columns (default 72). In multiline and grid tables, the width of each column in the source sets its relative width. In Quarto, use tbl-colwidths="[75,25]" after the caption.

Which Pandoc table format should I use?

Pipe tables for anything that also needs to render on GitHub or GitLab. Multiline tables when cells need wrapped text. Grid tables when you need merged cells, lists or code blocks in cells. Simple tables for small, quick, plain-text-readable tables.

Why does my Pandoc table caption not show up?

Check for a blank line between the table and the Table: line, that the input format is Pandoc Markdown (-f markdown; -f gfm and -f commonmark have no captions), and that the caption starts with Table: or :.

How do I reference a table in Quarto?

Add a label that starts with tbl- in braces at the end of the caption, : Fruit prices {#tbl-fruit}, then write @tbl-fruit in the text. For tables from code cells, use #| label: tbl-name and #| tbl-cap: "Caption".

Does Pandoc convert grid tables to GitHub Markdown?

Yes, with pandoc -t gfm. Simple grids become pipe tables, but merged cells are split into empty cells, and cells with lists or code blocks make Pandoc write the whole table as HTML, which GitHub renders.

Related: merged cells, math in tables, rendering tables in React and the Markdown table to HTML converter.