Skip to main content
tablesgfmsyntax

Markdown Table Syntax: Alignment, Examples & Generator

Build Markdown tables with correct GFM delimiters, column alignment, escaped pipes, accessible headers, examples, and a free table generator.

By mdkit Team···8 min read
On this page

A Markdown table needs a header row, a delimiter row, and matching pipe-separated cells. Add colons to the delimiter row for alignment, and escape literal pipes with \|.

Use tables for compact, genuinely tabular data. For broader syntax context, see the GFM reference; for immediate output, open the Markdown Table Generator.

Basic syntax

A Markdown table is a header row, a separator row, and one or more data rows. Each row starts and ends with a pipe (|) and uses pipes to separate cells.

| Name | Role | Location | | -------- | ---------- | --------- | | Ada | Engineer | London | | Grace | Admiral | Arlington | | Katherine| Scientist | Hampton |

Renders as:

NameRoleLocation
AdaEngineerLondon
GraceAdmiralArlington
KatherineScientistHampton

The separator row (the second line) is what tells the parser this is a table. Each delimiter cell needs at least one hyphen in formal GFM, though three or more (---) is the clearest convention.

Column alignment

You control alignment with colons in the separator row:

| Left | Center | Right | | :-------- | :-------: | ------: | | apples | 2 | $1.50 | | bread | 1 | $4.25 | | eggs | 12 | $6.00 |
  • :--- left-align (default)
  • :---: center
  • ---: right-align

Right-align numeric columns. Center headers. Left-align text. That's the rule — don't overthink it.

Inline formatting inside cells

Links, bold, italic, inline code, and images all work:

| Feature | Status | Docs | | --------------- | --------- | -------------------------- | | **Auth** | ✅ Shipped | [Guide](/docs/auth) | | *Billing* | 🟡 Beta | `/api/billing` | | ~~Legacy sync~~ | ❌ Removed ||

Emoji can make status columns compact, but include text or an accessible label when the symbol's meaning is not obvious.

Escaping pipes

If a cell value contains a pipe, escape it with a backslash or use HTML entities:

| Operator | Meaning | | -------- | -------------------- | | `\|` | Pipe / bitwise OR | | `\|\|` | Logical OR | | `&` | Bitwise AND |

Code spans do not automatically protect pipes because GFM identifies table cells before parsing inline code. Write `a \| b` and preview it in your renderer; if portability matters, rephrase the cell or use an HTML table.

Multiline content inside cells

Markdown tables are strictly single-line per row. You cannot do this:

| Col | | --- | | Line 1 Line 2 |

The parser will break. Instead, use a <br> tag:

| Steps | | --------------------------------------------- | | 1. Clone repo<br>2. Run `npm install`<br>3. Start dev server |

For anything more complex — paragraphs, code blocks, lists — switch to raw HTML:

<table> <thead> <tr><th>Name</th><th>Description</th></tr> </thead> <tbody> <tr> <td>Setup</td> <td> <ol> <li>Clone the repo</li> <li>Install dependencies</li> <li>Run migrations</li> </ol> </td> </tr> </tbody> </table>

Raw HTML handling and sanitization vary by platform. Confirm the target renderer permits the elements you use.

Empty cells

Leave the cell blank but keep the pipes:

| Name | Email | Phone | | ---- | -------------- | ---------- | | Ada | [email protected] | | | Bob | | 555-0100 |

Don't use N/A or - unless the absence of data is itself meaningful. Blank is cleaner.

Minimum viable table

These all render correctly:

|a|b| |-|-| |1|2|
a|b -|- 1|2

The leading and trailing pipes are optional in GFM, though most style guides (and code formatters like Prettier) add them for consistency. Always use them — the visual bracketing helps humans read the source.

Column widths don't exist

There's no syntax for setting column width in Markdown tables. The rendered width is determined by content and the container's CSS. If you need fixed widths, use HTML with <col style="width: 20%"> or wrap the table in a div with a max-width and horizontal scroll.

When tables break down

Reach for alternatives when:

  • The table is hard to scan at the target width. Consider a definition list (<dl>) or a series of cards.
  • Rows need multi-paragraph content. Use an HTML table or a list of sections with headings.
  • You need sorting, filtering, or pagination. That's a web app feature, not a document feature. Export the data as JSON/CSV and render it with a proper data grid.
  • The table is really a form. Use HTML inputs.
  • Readers need to scan many rows. Consider pagination, a separate data view, or a downloadable CSV.

Tables in READMEs

Common README table patterns:

Feature comparison:

| Feature | Free | Pro | Enterprise | | ------------- | :--: | :-: | :--------: | | 5 projects | ✅ | ✅ | ✅ | | Unlimited | ❌ | ✅ | ✅ | | SSO | ❌ | ❌ | ✅ | | SLA | ❌ | ❌ | ✅ |

Environment variables:

| Variable | Required | Default | Description | | ------------- | :------: | ----------- | --------------------------- | | `PORT` || `3000` | HTTP server port | | `DATABASE_URL`||| Postgres connection string | | `LOG_LEVEL` || `info` | One of `debug`/`info`/`warn`|

Browser / platform support:

| Platform | Version | Supported | | -------- | ------- | :-------: | | Chrome | 120+ || | Firefox | 120+ || | Safari | 17+ || | IE 11 |||

These are useful starting patterns for READMEs; adapt labels and accessibility cues to the project.

Generating tables from data

Writing tables by hand is tedious. A few automation paths:

  • With a grid editor: enter cells in the Markdown Table Generator, set alignment, and copy the generated Markdown. Spreadsheet-range import is not currently supported.
  • From CSV: pandoc data.csv -t gfm -o out.md handles escaping and alignment.
  • From code/JSON: a small script using a library like markdown-table (Node) or tabulate (Python) generates clean output.
  • From a database query: most CLI database clients (psql, mysql) have a Markdown or "pretty" output mode.

If you find yourself hand-editing a 20-row table, stop and script it.

Accessibility notes

  • Always include a header row. Screen readers announce columns using header text.
  • Keep cells short. Long cells are hard to scan with keyboard navigation.
  • Don't use tables for layout. Tables are for tabular data. If you're using a table to arrange unrelated content side-by-side, use CSS Grid or Flexbox (via raw HTML) instead.
  • Provide a caption or preceding heading. This gives the table semantic context. In raw HTML: <caption>. In Markdown: a heading right above the table serves the same purpose.

Troubleshooting

"My table renders as plain text." The delimiter row is missing or malformed. Each cell needs at least one hyphen, optional alignment colons, and the row must immediately follow the header.

"Columns are misaligned in the rendered output." You have the wrong number of cells in a row. Count pipes — each row should have the same count as the header.

"A pipe inside my cell breaks the table." Escape it with \|, including when the pipe appears inside a code span.

"The table is too wide and overflows." Markdown has no width controls. Wrap the rendered table in a scrolling container via CSS, or reduce columns, or switch to a different layout (list, cards).

"Alignment colons aren't working." Some older parsers (especially pre-GFM ones) ignore alignment. Confirm your renderer supports GFM tables.

Quick reference

| Left | Center | Right | | :---- | :----: | ----: | | a | b | c | | long | longer | 1,234 |
  • Leading/trailing pipes: optional but recommended
  • Delimiter row: required; one hyphen is valid GFM, while three or more is clearer
  • Alignment: :--- left, :---: center, ---: right
  • Escape pipes with \|, even in code spans
  • Use <br> for line breaks inside cells
  • Drop to raw HTML for complex content

Bookmark this page. Tables are the one Markdown feature you'll keep forgetting the fiddly details of — that's normal.

Frequently Asked Questions

Does standard Markdown support tables?+
No. CommonMark does not include tables. Tables are a GFM extension and are also available in many other processors, but you should verify the target renderer's syntax and alignment support.
How do I escape a pipe character inside a table cell?+
Use a backslash: `\|`. GFM recognizes cell boundaries before parsing inline content, so a pipe inside a code span can still split the row; escape it and preview the result.
Can I put lists, code blocks, or images inside table cells?+
Inline elements (links, bold, italic, inline code, images) work fine. Block elements like fenced code blocks, multi-line lists, or blockquotes do not — Markdown tables are single-line per row. For complex cell content, drop to raw HTML with `<table>` or use `<br>` tags for line breaks.
Why does my table look misaligned in the source but render fine?+
The renderer only cares about the pipe structure, not visual alignment of the source. You can write `|a|b|c|` on one row and `| long | cells | here |` on the next and both render identically. Formatting source columns is for human readability only.
What's the easiest way to generate a Markdown table from a spreadsheet?+
Copy the cells from Excel or Google Sheets, paste into a tool like the Markdown Table Generator, and export. Or use Pandoc: `pandoc data.csv -t gfm -o table.md`. For one-offs, even a simple find-and-replace (tabs to pipes) works.

Keep reading