HTML to Markdown Converter

Everything runs in your browser. Your HTML and Markdown are not uploaded, logged, or stored.
HTML input
Markdown output
Rendered preview

How to Convert HTML to Markdown

Paste HTML into the left panel and the Markdown appears on the right as you type. You can paste raw source (a whole page from View Source, or just a fragment), or copy a section of any web page, Google Doc or Word document and paste it straight in. With Rich paste ticked, the tool takes the formatted HTML version your browser puts on the clipboard instead of the plain text, so headings, links, bold text and lists come through.

The converter parses your HTML with the browser's own HTML parser, the same one that renders web pages, so unclosed tags and messy markup are handled the way a browser would handle them. It then walks the document and writes GitHub Flavored Markdown: CommonMark plus tables, strikethrough and task lists. Scripts, styles, iframes, buttons and form fields are dropped. Nothing is sent to a server, which matters when the page you are converting is an internal wiki, a private doc or an email.

Click Markdown → HTML to go the other way, or Use as Input ⇄ to feed the result back in and check that the conversion round-trips. The rendered preview under the panels shows the HTML side as a browser displays it. It runs in a sandboxed frame with scripts disabled.

HTML to Markdown Reference

This is what the HTML to Markdown converter writes for each element. Every row was produced by pasting the HTML into the tool above.

HTMLMarkdown output
<h2>Install</h2>## Install
<strong>, <b>**bold**
<em>, <i>*italic*
<strong><em>both</em></strong>**_both_**
<del>, <s>, <strike>~~old~~
<code>a `b` c</code>``a `b` c``
<a href="…" title="…">[text](url "title")
<a href="https://example.com">https://example.com</a><https://example.com>
<img src="/logo.png" alt="Logo">![Logo](/logo.png)
<br>A backslash at the end of the line
<blockquote>> before every line, nested quotes become > >
<hr>---
<ol start="3">3. three, 4. four
<input type="checkbox" checked> in <li>- [x] Done
<sup>, <sub>, <kbd>, <u>, <mark>Kept as inline HTML, e.g. mc<sup>2</sup>
<script>, <style>, <iframe>, <button>Removed
<div>, <span>, <section>Unwrapped; only their content is kept

Tables, Nested Lists and Code Blocks

These three are where most HTML to Markdown converters fail. Tables get flattened into lines of text, nested lists lose their indentation, and code blocks lose their language or break when the code itself contains backticks. This tool keeps all of them.

Tables become GFM pipe tables. Column alignment is read from the align attribute or from an inline text-align style, so a right-aligned price column stays right-aligned:

HTML in
<table>
  <tr><th>Plan</th><th align="right">Price</th><th align="center">Users</th></tr>
  <tr><td>Free</td><td align="right">$0</td><td align="center">1</td></tr>
  <tr><td>Team</td><td align="right">$12</td><td align="center">10</td></tr>
</table>
Markdown out
| Plan | Price | Users |
| --- | ---: | :---: |
| Free | $0 | 1 |
| Team | $12 | 10 |

A pipe character inside a cell is escaped as \|, including inside inline code, so <code>a | b</code> in a cell becomes `a \| b` and still renders as a | b. A <br> inside a cell is written as a literal <br>, because a Markdown table row has to stay on one line.

Nested lists are indented by the width of the parent's marker, which is what CommonMark requires, so a numbered list inside a bullet keeps its nesting when it is rendered again:

HTML in
<ul>
  <li>Backend
    <ol>
      <li>Install Node</li>
      <li>Run <code>npm ci</code></li>
    </ol>
  </li>
  <li>Frontend</li>
</ul>
Markdown out
- Backend
  1. Install Node
  2. Run `npm ci`
- Frontend

Code blocks become fenced blocks with a language hint. The language is taken from a language-* or lang-* class (the convention used by Prism, highlight.js and most Markdown renderers), from GitHub's highlight-source-* wrapper, or from a data-lang attribute. So <pre><code class="language-python"> opens with ```python. Whitespace inside <pre> is kept exactly, including indentation and blank lines. If the code itself contains three backticks, the fence is made longer, so Use ```js to open a fence is wrapped in four backticks and does not end the block early.

Markdown to HTML

Switch the direction and the tool becomes a Markdown to HTML converter. It implements CommonMark, including its rules for emphasis, link reference definitions, setext headings and lazy continuation lines, plus the GitHub extensions for tables, ~~strikethrough~~ and task lists. We converted thousands of randomly generated documents with both this tool and markdown-it, the parser behind many documentation sites, and the output matched. The only differences were a few contrived cases of unmatched * or _ runs inside link text, such as [*w=**](url); there markdown-it departs from commonmark.js, the CommonMark reference implementation, and this tool gives the reference result.

A few behaviours worth knowing:

Converting Copied Web Pages and Google Docs

When you copy formatted text, the clipboard holds two versions: plain text and HTML. A normal paste into a text box uses the plain text. With Rich paste on, this tool reads the HTML version, so you can select an article in your browser, copy it and paste it here to get Markdown with the headings, links and lists intact. Untick the option to paste plain text instead, for example when you are pasting HTML source code that you copied from an editor.

Google Docs does not use <strong> and <em>. It marks bold, italic and strikethrough with inline styles such as <span style="font-weight:700">, and it wraps the whole paste in <b style="font-weight:normal">. The converter reads those styles, so pasted Docs text comes out as **Bold** and *italic* text rather than either losing its formatting or turning bold everywhere.

What Markdown Cannot Express

Markdown is smaller than HTML, and some things have no equivalent. This is what the tool does with them:

Common Mistakes When Converting HTML to Markdown

How to Convert HTML to Markdown in Code

For a one-off conversion, paste into the tool. To convert many files, use a library. In JavaScript, Turndown is the standard choice. Tables and strikethrough need its GFM plugin:

import TurndownService from 'turndown';
import { gfm } from 'turndown-plugin-gfm';

const td = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced' });
td.use(gfm);
const markdown = td.turndown('<h2>Install</h2><p>Run <code>npm ci</code></p>');

In Python, use markdownify:

from markdownify import markdownify as md

markdown = md(html, heading_style="ATX")

From the command line, Pandoc converts files in both directions:

pandoc -f html -t gfm page.html -o page.md
pandoc -f gfm -t html page.md -o page.html

For Markdown to HTML in JavaScript, markdown-it and marked are the usual libraries. Whatever you use, render Markdown from untrusted users through an HTML sanitiser, because Markdown allows raw HTML. Many Markdown files also start with a YAML front matter block between --- lines; the YAML to JSON converter will show you what that metadata parses to.

Frequently Asked Questions

How do I convert HTML to Markdown?
Paste the HTML into the left panel of this HTML to Markdown converter and copy the Markdown from the right panel. You can paste HTML source or copy formatted text from a web page or document. Everything runs in your browser and nothing is uploaded.
Does the converter keep tables?
Yes. HTML tables become GitHub Flavored Markdown pipe tables, with column alignment read from the align attribute or text-align style. Pipes inside cells are escaped as \|, and line breaks inside a cell are written as <br>.
Can I convert Markdown to HTML as well?
Yes. Click "Markdown → HTML". The converter follows CommonMark with GitHub's tables, strikethrough and task lists, and it was tested against markdown-it and the CommonMark reference implementation. The rendered preview shows the result.
How are code blocks converted?
<pre> blocks become fenced code blocks with the language taken from a class such as language-python. Indentation and blank lines are kept. If the code contains backticks, the fence is made longer so the block does not end early.
Can I paste from Google Docs?
Yes. With Rich paste on, the tool reads the formatted version from the clipboard. It recognises the inline styles that Google Docs uses for bold, italic and strikethrough, so they become **bold**, *italic* and ~~strikethrough~~.
Why is some of my output still HTML?
Markdown has no syntax for superscript, subscript, underline, keyboard keys or highlighting, so those are kept as inline HTML, which Markdown allows. Emphasis that cannot be written safely with *, such as <em>(optional)</em>value, is also kept as HTML so it renders correctly.
Is it safe to paste private content?
Yes. The conversion runs entirely in your browser with JavaScript. Nothing you paste is sent to a server, and the preview frame is sandboxed so scripts in pasted HTML do not run.