toolhq.io

All posts
5 min readby Jameel Haider

Markdown tables and formatting: alignment, escaping pipes, and GFM gotchas

Markdown tables are not part of the CommonMark core specification. They come from GitHub Flavored Markdown, which is why a table that renders cleanly on GitHub can come out as literal pipe characters in a plain CommonMark renderer. Knowing where that line sits saves a lot of confusion.

Basic table syntax

A table is a header row, a delimiter row of dashes, and one or more body rows, with cells separated by pipes:

| Name  | Role     | Active |
|-------|----------|--------|
| Alice | Engineer | yes    |
| Bob   | Designer | no     |

The delimiter row is mandatory and defines the table. Without it, the lines are just text with pipes in them. The leading and trailing pipes on each row are optional, so Name | Role works, but keeping them makes the source readable. The columns do not need to line up visually in the source; renderers ignore the spacing. Aligning them by hand is purely for the humans reading the raw file.

Column alignment with colons

Colons in the delimiter row set each column's text alignment:

| Left | Center | Right |
|:-----|:------:|------:|
| a    | b      | c     |
DelimiterAlignment
:---Left
:--:Center
---:Right
---Default, usually left

The colon goes on the side you want the text pulled toward: left colon for left, both for center, right colon for right. This is the one piece of table styling Markdown gives you; there is no way to set column width, merge cells, or span rows in standard Markdown.

Escaping pipes

The pipe is the column separator, so a literal pipe inside a cell breaks the table by creating a phantom column. Escape it with a backslash:

| Operator | Meaning        |
|----------|----------------|
| `\|\|`     | Logical OR     |
| `a \| b`   | a or b         |

The gotcha: escaping interacts awkwardly with inline code. Inside backticks, Markdown normally treats characters literally, but the pipe is still seen as a column boundary by the table parser, so you often still need the backslash even inside code. When a cell with code and pipes refuses to render, this is almost always why.

Line breaks inside a cell are the other limit. A table cell cannot contain a hard line break in standard syntax; the workaround is a literal <br> tag, which works because GFM permits inline HTML, but it is a renderer dependent crutch rather than real Markdown.

Where GFM extends CommonMark

CommonMark is the strict, portable base: headings, lists, emphasis, links, code, block quotes. GFM adds the features developers assume are universal but are not:

  • Tables, as above.
  • Task lists with - [ ] and - [x].
  • Strikethrough with ~~text~~.
  • Autolinking bare URLs without angle brackets.

If your content must render identically everywhere, treat these as GFM only and test in the target renderer. A document full of task lists and tables is firmly GFM and will degrade to visible syntax in a strict CommonMark environment.

The practical habit

Write tables with the pipes aligned in the source even though the renderer ignores it, escape every literal pipe, and preview in a renderer that matches your target before publishing. Most table bugs are a missing delimiter row, an unescaped pipe, or an assumption that CommonMark supports a GFM feature.

Paste your Markdown and watch it render live, tables and all, with the Markdown Preview to catch these issues before they ship.