TSV to Markdown Table Converter

The fastest route from a spreadsheet to a README. Copy the cells, paste them here, get a Markdown table with the pipes escaped and the numbers aligned.

To convert TSV to a Markdown table, paste your tab-separated text above. Copying cells from any spreadsheet puts exactly this on your clipboard, so no file is needed. The header row becomes the table header, numeric columns are right-aligned, pipes inside values are escaped and line breaks become br.

Want to trim the columns first? Open the app

The clipboard shortcut nobody mentions

Every spreadsheet puts tab-separated text on the clipboard when you copy cells. That means the fastest path from a spreadsheet to a Markdown table involves no file, no export and no download: select, copy, paste here, copy the result.

It works from Excel, from Numbers, from Google Sheets, from a database client's result grid and from most BI tools' table views. Anywhere you can select rows and press copy, you have a TSV.

Which is why this page pins the tab as its separator rather than sniffing: clipboard content is frequently a handful of rows, far too little for any delimiter heuristic to be confident about.

Tab-separated, declared rather than guessed

Most converters sniff the delimiter by counting candidates in the first few lines. That works until it does not, and when it fails it fails completely: a tab-separated export whose first rows hold several commas each gets read as a CSV, and every row comes back as one column of text with tabs inside it.

Because this page declares tab-separated input, the separator is pinned rather than sniffed. A file full of commas, semicolons and pipes still splits on tabs, which is what the file says it is.

That is the whole argument for having a TSV page distinct from the CSV one. Everything else about the two is the same; the difference is that this one cannot guess wrong.

Worked example

Cells copied out of a spreadsheet, tabs shown as gaps:

store_code    city              staff   revenue
0041          Osaka, Japan      12      1840.50
0058          Berlin            7       975.00

And the Markdown:

| store_code | city | staff | revenue |
| --- | --- | ---: | --- |
| 0041 | Osaka, Japan | 12 | 1840.50 |
| 0058 | Berlin | 7 | 975.00 |

Only staff is right-aligned. store_code looks numeric and is an identifier with a padded zero, so it stays left. revenue looks numeric and holds 1840.50, which does not round trip as a number, so the column is text and stays left too. Alignment follows the type, and the type follows the whole column.

The three things that break a Markdown table

A pipe inside a value ends the cell. Spreadsheet cells hold pipes in makeshift lists and in anything copied from a log. Every one is escaped as \|, with backslashes escaped first so a value ending in one cannot consume the escape after it.

A line break inside a cell, typed with alt and enter, ends the row, and Markdown has no continuation. Those become <br>, which GitHub renders as a line break inside the cell.

A column that looks numeric but is not gets left alignment, because auto alignment reads the type rather than the characters. A competing converter right-aligns a padded code column having just typed it as text, which presents an identifier as a quantity.

Where the table is going

A README is the obvious destination and not the most common one. The frequent uses are a pull request description, where the table is the evidence for a change, and an issue, where it is the evidence for a bug. Both are read by people who will not open a spreadsheet you attach.

Wikis are the third. Most of them, including GitHub's, take Markdown, and a table pasted as Markdown stays editable by the next person. A screenshot does not, and six months later the numbers in it are pixels.

The fourth is a chat message. Slack renders a fenced code block faithfully, so a Markdown table pasted inside one keeps its alignment even where the table syntax itself is not rendered.

Practical notes

  • Columns are not padded to a common width in the source. It costs a great many characters on a wide table, no renderer takes any notice, and it makes the next diff unreadable.
  • Four alignments are available: auto, all left, all centered and all right. Auto is the default and right-aligns numeric columns only.
  • Above about ten thousand rows you get a note. Nothing is blocked, but a table that long renders slowly on GitHub and nobody scrolls it.
  • Everything is reported: ragged rows padded, blank headers named, duplicate headers renamed, all with counts.
  • Nothing is uploaded, and no attribution comment is added to the output.

Frequently Asked Questions

Can I paste straight from a spreadsheet?

Yes, that is the main way to use this page. Copying cells from Excel, Numbers, Google Sheets or a database client's result grid puts tab-separated text on the clipboard, so no file is involved at any point.

Why is the tab pinned rather than detected?

Because clipboard content is often only a few rows, which is far too little for a delimiter heuristic to be confident about. Declaring the separator means a handful of pasted rows containing commas still splits correctly.

Why is my revenue column left-aligned?

Because 1840.50 does not round trip as a number, so the whole column is text. Alignment follows the type decided from all the values rather than the shape of the characters, which is what keeps identifiers from being presented as quantities.

Are pipes escaped?

Every one, with backslashes escaped first so a value ending in a backslash cannot eat the escape on the pipe that follows. One unescaped pipe breaks the entire table where it renders.

What happens to a cell with two lines in it?

It becomes a br, which GitHub renders as a line break inside the cell. Markdown has no way to continue a table row, so the alternative would be silently joining the two lines.

Are the columns padded so the source lines up?

No. Padding costs a lot of characters on a wide table, no Markdown renderer looks at it, and it makes the next diff on the file unreadable. The rendered table is identical either way.

Spreadsheet to README in two pastes

Copy the cells, paste here, copy the table. Pipes escaped, numbers aligned.

Back to the converter