Markdown Tables: Syntax, Alignment, and When to Use Them
A Markdown table is three pieces stacked on top of each other: a header row, a delimiter row made of hyphens, and one or more data rows, all separated by pipes (|). Alignment is set entirely in that delimiter row, using colons. That's the whole syntax. The rest of this guide is the detail worth knowing so your tables render the way you expect on the first try.
Tables show up constantly once you're writing anything technical: comparison charts, config option references, changelogs, spec sheets. But the syntax is easy to half-remember and get subtly wrong. Below: how to build one, how alignment actually works, and where a Markdown table stops being the right tool.
Building a Basic Table
Every GitHub Flavored Markdown table needs exactly three parts: a header row, a delimiter row, and zero or more data rows, each with cells separated by pipes.
| Format | Extension | Renders inline |
|----------|-----------|-----------------|
| Markdown | .md | Yes |
| HTML | .html | Yes |
| Plain text | .txt | No |The header row names your columns. The delimiter row — the line of hyphens right below it — tells the renderer "this is a table," not a paragraph with some stray pipe characters in it. GitHub's own docs call for a minimum of three hyphens per column (---), though you can add more to pad a column out visually in the source. Data rows follow the same pipe-separated pattern as the header.
A couple of formatting habits keep the source file readable, not just the rendered output:
- Leading and trailing pipes on each row are optional, but adding them removes any ambiguity about where a row starts and ends. Worth doing once a table has more than two or three columns.
- To put a literal pipe character inside a cell — documenting a shell pipeline, say — escape it as
\|. Skip the escape and the parser reads it as a new column boundary.
Starting from a spreadsheet or a CSV export instead of typing a table by hand? Converting a spreadsheet or CSV into a table is usually faster than retyping every cell.
Alignment: Left, Right, and Center
Alignment lives entirely in the delimiter row, controlled by where you put a colon relative to the hyphens:
| Left | Center | Right |
|:---------|:--------:|---------:|
| Row 1 | Row 1 | Row 1 |
| Row 22 | Row 22 | Row 22 |- A colon on the left only (
:---): left-aligned. - Colons on both sides (
:---:): centered. - A colon on the right only (
---:): right-aligned. - No colon at all (
---): the renderer's default, which is effectively left-aligned in most implementations.
Both the GFM spec and Pandoc's table documentation describe this the same way, since GFM's pipe-table syntax and Pandoc's pipe tables are close cousins. One detail trips people up: the columns in your source file do not need to visually line up for any of this to work. A renderer parses pipe positions, not whitespace, so a delimiter row of |:-|:-:|-:| behaves identically to one padded out with extra hyphens for readability. Lining columns up with spaces is purely a courtesy to the next human reading the raw file.
Alignment syntax is a small, easy-to-forget extension on top of base Markdown, in the same family as GFM-only extensions like autolinking bare URLs. Those work in GitHub and most GFM-compatible renderers but aren't part of the original Markdown spec.
What Tables Can't Do (and When to Reach for HTML)
A GFM table cell only holds inline content: text, bold, italics, inline code, links. No block-level elements. No bulleted lists, no multiple paragraphs, no nested tables, no blockquotes. Try to put a list inside a cell and most renderers will either flatten it into plain text separated by stray characters or break the table outright, per the GFM spec.
GFM tables also assume a header row — there's no built-in syntax for a header column (a table where the left-hand cell in each row is the label instead). MDN's own writing guidelines recommend dropping to a raw HTML table for that case, along with a few others:
- You need
colspan,rowspan, or a<caption>. - Cells need to hold a list, multiple paragraphs, or other block content.
- The Markdown source would be uncomfortably wide. MDN's own cutoff is around 150 characters per row, and past that HTML is genuinely easier to read and maintain than one giant single-line table.
Here's the honest version of that trade-off: Markdown tables are great for the common case, a straightforward grid of short values, and a poor fit the moment you need real layout control. That's not a flaw in Markdown. It's a deliberate scope limit, and it's part of why the same Markdown file renders differently across parsers when someone tries to push GFM syntax past what it was designed to do. Curious what other GFM conveniences get missed entirely by some renderers? Definition lists and a few other Markdown extras are a related rabbit hole.
Doing This With Carets
Carets is a fast, native notes and code editor for iPhone, iPad, and Mac, and tables are exactly the kind of syntax where a plain-text editor either helps or gets in the way. Two things make the difference here:
- Syntax highlighting for Markdown and code. Carets highlights table pipes, delimiter rows, and colons distinctly from surrounding prose, so a broken alignment marker or a missing hyphen is easy to spot before you save, instead of finding out only when the file renders somewhere else.
- Your files stay plain text. A table you write in Carets is the same
.mdfile you'd commit to a README, paste into a GitHub comment, or run through Pandoc. No proprietary format standing between what you typed and what other tools expect.
Carets doesn't try to replace a spreadsheet or a full IDE, and a sprawling HTML table with colspan and rowspan is genuinely outside what a lightweight Markdown editor should try to render live. What it's built for is the everyday case: writing and editing a clean GFM table quickly, on whichever device you have open, without breaking your plain-text workflow to do it. Carets is available on iPhone, iPad, and Mac on the App Store.
Frequently Asked Questions
Do the columns in my Markdown table source need to line up visually?
No. Renderers only care about where the pipe characters are, not about whitespace padding, so a tightly packed row and a version with extra spaces added to visually align columns produce identical output. Lining columns up in your editor is a readability courtesy for other humans reading the raw file, not a syntax requirement.
How many hyphens does the delimiter row need?
At least three per column, per the GitHub Flavored Markdown spec, so --- is valid but - or -- is not. You can add more hyphens to make a column visually wider in the source without changing how it renders.
Can I put a list or multiple paragraphs inside a table cell?
No. GFM tables only allow inline content (text, bold, italics, code spans, links) inside a cell. Block-level elements like lists, blockquotes, or additional paragraphs aren't supported, and a renderer will typically flatten them into plain inline text or break the table. If you need that, use an HTML table instead.
What does center alignment look like in the delimiter row?
Put a colon on both sides of the hyphens: :---:. A colon only on the left (:---) is left alignment, a colon only on the right (---:) is right alignment, and no colon at all leaves the column at the renderer's default alignment.
Conclusion
That's the entire syntax: three rows (header, delimiter, data), pipes to separate columns, colons in the delimiter row to set alignment. Once that's automatic, the more useful skill is recognizing when a table is the wrong tool — a header-column layout, a cell that needs a list, a row so wide it stops being readable — and reaching for HTML instead of forcing GFM syntax past its scope.