Markdown Table to HTML Converter

One table, one element. Paste a Markdown table and get semantic markup with a real header, escaped values and alignment taken from the data rather than the source.

To convert a Markdown table to HTML, paste the table above. The header row becomes th cells inside a thead, each data row becomes a tr in a tbody, escaped pipes come back as plain pipes, a br stays a br, and every value is escaped so nothing in your data can break the page. Take a bare fragment or a complete styled document.

Need to edit the rows first? Open the app

Why not just run a Markdown renderer

Because a Markdown renderer converts the whole document. You wanted the table, and you got the table wrapped in whatever the renderer thinks a document looks like, with the surrounding prose, the heading and often a set of wrapper elements and generated ids you now have to strip out.

There is a subtler problem too. Every renderer emits slightly different table markup, some of them add classes, some emit alignment as inline styles, and none of them looks at your data. This one converts the table into a rectangle first and then writes markup for that rectangle, which is why the alignment can follow the column type instead of the colons somebody typed.

Worked example

The release table, alignment row and all:

| service | version | released | replicas | notes |
|:--------|--------:|:--------:|---------:|:------|
| billing-api | 2.4.1 | 2026-01-08 | 6 | rollout paused<br>resumed 09 Jan |
| web-frontend | 5.0.0 | 2026-01-12 | 4 | canary 10% \| full 14 Jan |
| search-index | 1.19.3 | 2026-01-15 | 12 | |

And the fragment:

<table>
  <thead>
    <tr><th>service</th><th>version</th><th>released</th><th class="num">replicas</th><th>notes</th></tr>
  </thead>
  <tbody>
    <tr><td>billing-api</td><td>2.4.1</td><td>2026-01-08</td><td class="num">6</td><td>rollout paused<br>resumed 09 Jan</td></tr>
    <tr><td>web-frontend</td><td>5.0.0</td><td>2026-01-12</td><td class="num">4</td><td>canary 10% | full 14 Jan</td></tr>
  </tbody>
</table>

Only replicas carries the num class, because it is the only column whose every value is a number. The source table's alignment row asked for version to be right-aligned and released to be centered; that is presentation somebody typed once and it is not carried over, because the data disagrees with it.

Escaping, and the round trip that catches people

An escaped pipe in Markdown is \| and it means a literal pipe. In HTML a pipe is an ordinary character and needs nothing. So the backslash is removed and the pipe is written plain, which is what the source actually meant.

Everything else goes the other way. An ampersand in your data becomes &amp;, an angle bracket becomes an entity, and an apostrophe becomes &#39; so the markup stays safe when it is pasted inside a single-quoted attribute or a JavaScript string. That last one is the escape most converters skip.

A <br> in the Markdown source is already HTML, and it comes through as a <br>, so a two-line cell renders as two lines. A cell that acquired a real newline some other way gets one too.

Inline Markdown inside a cell

A cell holding **bold** or [a link](https://example.com) comes out as those exact characters, escaped, not as <strong> or an anchor. This is a table converter rather than a Markdown renderer, and inline formatting is left alone.

That is the right default for the common case, which is that the cell holds data and the asterisks are part of it. If you genuinely want the inline syntax rendered, a full Markdown renderer is the tool for that job and there are good ones in every language.

Fragment, page, and no styling at all

  • Table only is a bare <table> with no doctype, no wrapper and no CSS. Paste it into an existing page.
  • Full HTML page adds a doctype, a character set, a title and a compact stylesheet with collapsed borders and a shaded header. Save it and open it.
  • Styling off drops the CSS and the num class, giving markup with no classes at all, which is what a strict content management system or a linter usually wants.
  • Caption adds a <caption>, which screen readers announce before the table contents. It defaults to nothing rather than to the heading, because a caption is a decision.

Frequently Asked Questions

Why not use a Markdown renderer instead?

A renderer converts the whole document and hands you the table wrapped in prose, headings and often generated ids you have to strip. This reads the table into a rectangle and writes markup for that, which is also what lets the alignment follow the data.

Does the source alignment row carry over?

No. The colons in the dashes row are presentation somebody typed once, and they frequently disagree with the data, right-aligning a version string for instance. Alignment here follows the column type, and a note tells you how many columns had explicit alignment in the source.

Is bold or a link inside a cell rendered?

No. A cell holding **bold** comes out as those characters, escaped. This converts a table, not a document, and in most real tables the asterisks are part of the data. Use a Markdown renderer if you want inline syntax processed.

What happens to an escaped pipe?

The backslash goes and the pipe is written plainly, because a pipe needs no escaping in HTML. That is the source's actual meaning: one cell containing a pipe character.

Are values escaped?

All five markup characters, apostrophe included. The apostrophe is the one most converters skip because it renders fine in a cell, and it is the one that breaks as soon as the markup is pasted inside a single-quoted attribute.

Can I get a complete page rather than a fragment?

Yes. The full page option wraps the table in a document with a doctype, a character set, a title and a small stylesheet, so you can save the file and open it in a browser without touching anything else.

One table, properly marked up

Semantic thead and tbody, everything escaped, no renderer required.

Back to the converter