I write a lot of markdown. Documentation, READMEs, blog posts, issue descriptions. And every time I need a table, I waste two minutes manually aligning pipes and dashes. Markdown tables are one of the format's worst-designed features, and there is no reason to type them by hand.
The markdown table syntax
A basic markdown table looks like this:
| Name | Type | Default |
|---------|--------|---------|
| width | number | 100 |
| height | number | 200 |
| visible | bool | true |
The rules:
- Columns are separated by pipes (
|) - The header row is followed by a separator row of dashes
- Each dash group must have at least three dashes
- Leading and trailing pipes are optional but conventional
- Column alignment is controlled by colons in the separator row
Alignment syntax:
| Left | Center | Right |
|:-------|:-------:|-------:|
| text | text | text |
This is all manageable for a three-column, three-row table. It becomes genuinely painful for anything larger.
Why manual tables break
The problem is not the syntax. It is maintenance. When you add a row with a longer value, every other row in that column needs re-padding to keep the source readable. Add a column, and every row needs a new pipe and padding.
Consider adding a "Description" column to the table above:
| Name | Type | Default | Description |
|---------|--------|---------|--------------------------------|
| width | number | 100 | Widget width in pixels |
| height | number | 200 | Widget height in pixels |
| visible | bool | true | Whether the widget is rendered |
Three columns became four. Every row needed editing. Every separator dash needed recounting. This is exactly the kind of repetitive formatting work that should be automated.
Converting from other formats
The most common scenario is converting data from another source into a markdown table. You have a CSV, a spreadsheet, a SQL result set, or a JSON array, and you need it in markdown.
CSV to markdown is the most common conversion:
name,type,default
width,number,100
height,number,200
visible,bool,true
The algorithm:
- Split into rows by newline
- Split each row by comma (handling quoted values)
- Calculate max width for each column
- Format with pipes and padding
- Insert separator row after header
function csvToMarkdown(csv) {
const rows = csv.trim().split('\n').map(r => r.split(','));
const colWidths = rows[0].map((_, i) =>
Math.max(...rows.map(r => (r[i] || '').length))
);
const formatRow = row =>
'| ' + row.map((cell, i) =>
(cell || '').padEnd(colWidths[i])
).join(' | ') + ' |';
const separator = '| ' + colWidths.map(w =>
'-'.repeat(w)
).join(' | ') + ' |';
return [formatRow(rows[0]), separator,
...rows.slice(1).map(formatRow)].join('\n');
}
JSON to markdown
API documentation often needs to present JSON object schemas as tables. Converting a JSON structure:
function jsonToMarkdownTable(arr) {
if (!arr.length) return '';
const keys = Object.keys(arr[0]);
const header = keys;
const rows = arr.map(obj => keys.map(k => String(obj[k] ?? '')));
return csvToMarkdown([header, ...rows].map(r => r.join(',')));
}
// Usage
jsonToMarkdownTable([
{ name: 'width', type: 'number', default: 100 },
{ name: 'height', type: 'number', default: 200 }
]);
Column alignment choices
Left-align text, right-align numbers. This is not a style preference. It is a readability convention with research behind it. Tabular number alignment allows the eye to scan down a column and compare magnitudes instantly. Left-aligned numbers force the reader to check digit count for each value.
| Metric | Value |
|:--------------|------:|
| Page views | 1,234 |
| Bounce rate | 42% |
| Avg. duration | 3:21 |
Common mistakes
Forgetting the separator row. Without the dash row, most markdown parsers render the table as plain text. It is the separator that triggers table rendering.
Inconsistent column counts. Every row must have the same number of columns. If one row has 3 pipes and another has 4, the table breaks. Empty cells still need their pipes: | | value | |.
Using pipes in cell content. If your cell content contains a literal pipe character, escape it with a backslash: \|. This is easy to forget and produces baffling rendering bugs.
Markdown in cells. Most parsers support inline formatting (bold, italic, code) inside table cells, but not block-level elements. You cannot put a list, heading, or code block inside a table cell.
For generating markdown tables from any input format, including visual grid editing, I keep a generator at zovo.one/free-tools/markdown-table-generator. Paste in your data, adjust columns, and copy the formatted markdown. Life is too short to count dashes.
I'm Michael Lip. I build free developer tools at zovo.one. 500+ tools, all private, all free.
Top comments (0)