HTML to Markdown

Convert HTML back into Markdown. Use it when you move content out of a CMS and into files, so it can live in git next to your code. Turndown does the conversion in this tab, with your choice of bullet, emphasis and heading style.

HTML Input
Markdown Output

1 HTML to Markdown example

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
<h2>Release notes</h2>
<p>Shipped <strong>2.4.0</strong> on 10 September.</p>
<ul>
  <li>Store credit at checkout</li>
  <li>Partial refunds <em>(beta)</em></li>
</ul>
<table>
  <thead><tr><th>Change</th><th>Impact</th></tr></thead>
  <tbody><tr><td>New pricing API</td><td>breaking</td></tr></tbody>
</table>
<blockquote><p>Upgrade before the 30th.</p></blockquote>
<pre><code>npm i checkout-sdk@2.4.0</code></pre>

Markdown

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## Release notes

Shipped **2.4.0** on 10 September.

-   Store credit at checkout
-   Partial refunds _(beta)_

| Change | Impact |
| --- | --- |
| New pricing API | breaking |

> Upgrade before the 30th.

```
npm i checkout-sdk@2.4.0
```

2 What converts and what is lost

Anything Markdown can say

Headings, emphasis, links, images, lists, blockquotes, code blocks, strikethrough and simple tables all convert cleanly.

Wrappers are unwrapped

A div with classes or a styled span loses its tag and keeps its text. An element with no text, such as an iframe or an embed, disappears. Save those embeds separately before you convert.

Tables with spans

A plain grid becomes a pipe table. Markdown has no rowspan or colspan, so a table that uses them stays as raw HTML, which is valid Markdown.

Round trips are lossy

HTML has several ways to write what Markdown writes one way. For example, both b and strong become **bold**. Convert back and forth and the text survives, but attributes and wrappers do not.

3 Scraped pages do not run here

The HTML is parsed into a detached document that is never attached to this page, so nothing in it renders and no script in it runs. However, the text inside script and style tags comes through as plain text, so cut the page down to the article before you paste it.

A typical migration exports the posts as HTML, converts them to Markdown and commits them as files. Plan time for cleanup afterwards. Editors like WordPress leave shortcodes such as [gallery], empty paragraphs and inline styles behind, and none of that has a Markdown equivalent.

How to use the HTML to Markdown tool

  1. Paste HTML into the HTML panel, or load a file with Upload HTML.
  2. Set Bullets, Emphasis and Headings to match your Markdown linter.
  3. Check the output: wrapper tags are removed and their text kept, and a table with rowspan or colspan stays as raw HTML.
  4. Click Copy Markdown, or Download to save the result as a .md file.

How to convert HTML to Markdown in code

JavaScript / Node.js

// npm i turndown turndown-plugin-gfm
const TurndownService = require("turndown");
const { gfm } = require("turndown-plugin-gfm");

const td = new TurndownService({
    headingStyle: "atx",        // # Heading rather than underlines
    codeBlockStyle: "fenced",
    bulletListMarker: "-",
    emDelimiter: "_",
});
td.use(gfm);                    // tables, strikethrough, task lists

// Strip the chrome a CMS export drags along
td.remove(["script", "style", "nav", "footer"]);

console.log(td.turndown(html));

Python

# pip install markdownify
from markdownify import markdownify as md

print(md(html, heading_style="ATX", bullets="-", strip=["script", "style"]))

# For a scraped page, cut it down to the article first
# pip install beautifulsoup4
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
article = soup.select_one("article") or soup.body
print(md(str(article), heading_style="ATX"))

Command line

# pandoc handles almost any pair of formats
pandoc -f html -t gfm article.html -o article.md

# Keep it readable: no line wrapping
pandoc -f html -t gfm --wrap=none article.html -o article.md

# A whole export directory
for f in export/*.html; do
  pandoc -f html -t gfm --wrap=none "$f" -o "${f%.html}.md"
done

Common errors and how to fix them

Embeds and iframes are missing from the output
An element with no text content has nothing to convert, so it drops out. Copy embed codes out of the source first and paste them back into the Markdown as raw HTML, which is valid Markdown.
Tables stayed as HTML
Markdown tables cannot express rowspan or colspan. A plain grid converts, while a table with merged cells is kept intact as HTML instead of being flattened.
A round trip did not give back the original HTML
It will not match byte for byte. HTML has several ways to write what Markdown writes one way, so attributes and wrapper elements are lost. The text survives, and the original markup does not.
The Markdown is full of blank lines and stray text
A WYSIWYG editor wrote the source, or the paste included script and style tags whose text comes through. Clean the HTML before converting, or run a Markdown linter over the result.

Good to know

The usual reason to convert HTML to Markdown is leaving a CMS: export the posts, convert them, and commit them as files so you no longer need a database to hold text. Plan time for cleanup. A long-running WordPress site contains shortcodes, inline styles and several generations of embed markup, and none of that has a Markdown equivalent.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

What happens to HTML that Markdown cannot express?

Wrapper tags such as a div with classes or a styled span are removed and their text is kept. An element with no text, such as an iframe, disappears. The one case kept as raw HTML is a table with rowspan or colspan, since raw HTML is valid Markdown.

Can I choose the list and emphasis characters?

Yes. Bullets takes a dash, asterisk or plus, Emphasis takes an underscore or asterisk, and Headings switches between # ATX and underlined headings. Match whatever your linter expects, since all of them parse the same way.

Are tables converted?

Yes, into GitHub-style pipe tables, as long as the HTML table is a plain grid. A table with rowspan or colspan has no Markdown equivalent, so the tool keeps it as HTML.

Will a round trip give me back exactly what I started with?

Close, but not byte for byte. Markdown has one way to write a heading, while HTML has several ways to produce the same result. Attributes, wrapper elements and whitespace are lost on the way, so the text survives and the original markup does not.

Is it safe to paste a whole scraped page?

Yes. The HTML is parsed in a detached document that never renders, so its scripts do not execute. However, the text inside script and style tags comes through as plain text, so cut the page down to the article first.

Going the other way

Markdown to HTML does the reverse, and the Markdown editor gives you a live preview while you clean up the result. Entities left in the text can be unwrapped with the HTML decoder.

More Data Converters

Browse all data converters

Copied to clipboard!