Why Convert HTML to Markdown
HTML is the language of the web. It is what browsers render, what CMSs store, and what WYSIWYG editors produce. But HTML is verbose by design. A simple bold paragraph requires opening and closing tags, attributes, and nesting rules that add visual noise when you just want to read or write content.
Markdown solves this by giving you a lightweight syntax that maps directly to HTML but is dramatically easier to read and write. Instead of <h2>Title</h2>, you write ## Title. Instead of <a href="url">link</a>, you write [link](url). The content stays the same. The cognitive overhead drops to near zero.
Converting HTML to Markdown is a common task in these situations:
- CMS migration -- moving content from WordPress, Drupal, or another HTML-based system to a Markdown-based platform like Hugo, Gatsby, Astro, or Docusaurus.
- Documentation projects -- converting existing HTML docs to Markdown for storage in Git repositories where Markdown renders natively.
- Content repurposing -- pulling article text from web pages for reuse in README files, newsletters, or internal wikis.
- Clean authoring -- stripping WYSIWYG bloat (inline styles, empty spans, nested divs) down to clean, semantic Markdown.
- AI and LLM pipelines -- converting web-scraped HTML to Markdown before passing it to language models, since Markdown uses fewer tokens and preserves structure.
The challenge is that HTML is more expressive than Markdown. Not every HTML element has a Markdown equivalent. A good converter handles the common cases cleanly and gives you sensible options for the edge cases. Let us walk through exactly how to do this.
The Complete HTML-to-Markdown Syntax Mapping
This table covers every HTML element that has a direct Markdown equivalent. Bookmark it as a reference. If you want to test these mappings interactively, paste any HTML snippet into the QTool HTML to Markdown converter and see the output instantly.
| HTML | Markdown | Notes |
|---|---|---|
<h1> to <h6> | # to ###### | One # per heading level |
<p> | Plain text + blank line | Paragraphs separated by empty lines |
<strong> / <b> | **text** | Double asterisks or underscores |
<em> / <i> | *text* | Single asterisks or underscores |
<del> / <s> | ~~text~~ | GFM extension |
<a href="url"> | [text](url) | Title attr: [text](url "title") |
<img src="url"> |  | Alt text becomes the label |
<ul><li> | - item | Also * or + as bullet |
<ol><li> | 1. item | Numbers auto-increment |
<blockquote> | > text | Nest with > > text |
<code> | `code` | Inline code |
<pre><code> | ```lang ... ``` | Fenced code block |
<hr> | --- | Also *** or ___ |
<br> | Two trailing spaces or \ | Line break within paragraph |
<table> | Pipe table | GFM extension (see below) |
<input type="checkbox"> | - [x] / - [ ] | GFM task lists |
Table Conversion Example
HTML tables convert to GitHub Flavored Markdown (GFM) pipe tables. This is one of the trickiest conversions because HTML tables support features like colspan, rowspan, and nested tables that pipe tables cannot represent.
<!-- HTML -->
<table>
<thead>
<tr><th>Name</th><th>Role</th><th>Status</th></tr>
</thead>
<tbody>
<tr><td>Alice</td><td>Admin</td><td>Active</td></tr>
<tr><td>Bob</td><td>Editor</td><td>Inactive</td></tr>
</tbody>
</table>
Converts to:
| Name | Role | Status |
|-------|--------|----------|
| Alice | Admin | Active |
| Bob | Editor | Inactive |
You can also generate these tables from scratch using the QTool Markdown Table Generator, which gives you a visual grid editor for creating perfectly aligned pipe tables.
Not all HTML converts cleanly. Elements like <div>, <span>, <form>, <iframe>, and any tag with inline styles have no Markdown equivalent. Good converters strip them or pass them through as raw HTML. Know what your converter does with unsupported elements before running a bulk conversion.
Using Online Converter Tools
For one-off conversions or quick content extraction, a browser-based tool is the fastest option. No installation, no dependencies, no configuration.
QTool HTML to Markdown is a free converter that runs entirely in your browser. Paste HTML on the left, get Markdown on the right. It handles all the common elements from the mapping table above, including tables, nested lists, code blocks, and images. Because it processes everything client-side with JavaScript, your HTML never leaves your machine.
After converting, you can verify the output by pasting the generated Markdown into the QTool Markdown Preview tool, which renders it as HTML so you can visually confirm the conversion preserved your content correctly.
When to use an online tool
- Converting a single article or page
- Quick cleanup of WYSIWYG output before committing to Git
- Extracting content from a web page for documentation
- Testing how a specific HTML pattern converts before writing automation
When to use a programmatic approach
- Batch-converting hundreds or thousands of pages (CMS migration)
- Building a pipeline that converts HTML dynamically (scraping, API responses)
- Needing custom conversion rules for proprietary HTML structures
- Integrating conversion into a CI/CD or build process
Converting HTML to Markdown with JavaScript
Turndown is the standard JavaScript library for HTML-to-Markdown conversion. It creates a DOM tree from your HTML, walks each node, and applies conversion rules to produce clean Markdown output. It works in both Node.js and the browser.
Installation
npm install turndown
# or
yarn add turndown
Basic Usage
import TurndownService from 'turndown';
const turndown = new TurndownService({
headingStyle: 'atx', // # style headings (not underline)
codeBlockStyle: 'fenced', // ``` blocks (not indented)
bulletListMarker: '-', // - for unordered lists
});
const html = `
<h2>Project Setup</h2>
<p>Install the <strong>dependencies</strong> first:</p>
<pre><code class="language-bash">npm install</code></pre>
<ul>
<li>Node.js 18+</li>
<li>npm or yarn</li>
</ul>
`;
const markdown = turndown.turndown(html);
console.log(markdown);
Output:
## Project Setup
Install the **dependencies** first:
```bash
npm install
```
- Node.js 18+
- npm or yarn
Custom Rules
Turndown lets you add custom rules for any HTML element. This is essential when converting HTML from a specific CMS or application that uses custom classes or non-standard markup.
// Convert custom callout divs to blockquotes
turndown.addRule('callout', {
filter: (node) => {
return node.nodeName === 'DIV'
&& node.classList.contains('callout');
},
replacement: (content) => {
return '\n> ' + content.trim().replace(/\n/g, '\n> ') + '\n';
}
});
// Strip all <script> and <style> tags completely
turndown.remove(['script', 'style']);
GFM Tables Plugin
Turndown does not convert tables by default. Install the GFM plugin to add table support along with strikethrough, task lists, and other GitHub Flavored Markdown features.
import { gfm } from 'turndown-plugin-gfm';
turndown.use(gfm);
const html = '<table><tr><th>Name</th><th>Age</th></tr><tr><td>Alice</td><td>30</td></tr></table>';
console.log(turndown.turndown(html));
// | Name | Age |
// |-------|-----|
// | Alice | 30 |
Converting HTML to Markdown with Python
Python developers have two solid options: markdownify for simple conversions and html2text for more aggressive cleanup.
markdownify
pip install markdownify
from markdownify import markdownify as md
html = """
<h1>Welcome</h1>
<p>This is a <strong>test</strong> with a
<a href="https://example.com">link</a>.</p>
<ul>
<li>Item one</li>
<li>Item two</li>
</ul>
"""
result = md(html, heading_style="ATX", bullets="-")
print(result)
Output:
# Welcome
This is a **test** with a [link](https://example.com).
- Item one
- Item two
html2text
pip install html2text
import html2text
converter = html2text.HTML2Text()
converter.body_width = 0 # No line wrapping
converter.protect_links = True # Don't break long URLs
converter.ignore_images = False # Include image references
result = converter.handle(html)
print(result)
The key difference: markdownify aims for a one-to-one mapping that preserves the original structure. html2text is more opinionated and aggressively strips formatting to produce cleaner, more readable output. Choose based on whether you need structural fidelity or readability.
Command-Line Conversion with Pandoc
Pandoc is the Swiss Army knife of document conversion. It converts between dozens of formats, including HTML to Markdown, and handles edge cases that simpler tools miss.
# Install
brew install pandoc # macOS
apt install pandoc # Ubuntu/Debian
choco install pandoc # Windows
# Convert a file
pandoc input.html -f html -t markdown -o output.md
# Convert from stdin
curl -s https://example.com | pandoc -f html -t markdown
# Use GitHub Flavored Markdown output
pandoc input.html -f html -t gfm -o output.md
# Batch convert all HTML files in a directory
for f in *.html; do
pandoc "$f" -f html -t gfm -o "${f%.html}.md"
done
Pandoc is the best choice for CMS migrations where you need to convert hundreds or thousands of HTML files. It handles complex nesting, metadata extraction, and produces consistently clean output. For formatting the source HTML before converting, you can clean it up with the QTool HTML Beautifier to make the structure easier to inspect.
Edge Cases and Gotchas
The happy path of HTML-to-Markdown conversion is straightforward. The edge cases are where things get interesting. Here are the patterns that trip up converters and developers.
1. Inline Styles and Classes
Markdown has no concept of CSS. Inline styles like <span style="color:red">text</span> are silently stripped by most converters. If color, font size, or custom styling matters, you lose it in the conversion. The workaround is to keep the raw HTML in your Markdown file, since most Markdown renderers pass through HTML unchanged.
2. Nested Lists
Nested lists are the single most error-prone conversion. HTML allows arbitrary nesting of <ul> and <ol> elements. Markdown requires precise indentation (typically 2 or 4 spaces) to indicate nesting level. Off-by-one indentation errors cause Markdown parsers to flatten the list or break the structure entirely.
<!-- This HTML... -->
<ul>
<li>Parent
<ul>
<li>Child
<ul>
<li>Grandchild</li>
</ul>
</li>
</ul>
</li>
</ul>
<!-- ...must become exactly this: -->
- Parent
- Child
- Grandchild
3. Mixed Content in Paragraphs
HTML allows complex inline content: images inside links, links inside bold text, code spans containing special characters. Converters must handle combinations like <a href="url"><strong>bold link</strong></a>, which becomes [**bold link**](url). Not all converters get this right.
4. Empty Tags and Whitespace
WYSIWYG editors love inserting empty <p> tags, <br><br> sequences, and non-breaking spaces ( ). Good converters normalize this whitespace. Bad converters produce Markdown with excessive blank lines or literal strings.
5. HTML Entities
Entities like &, <, >, —, and © need to be decoded to their literal characters in Markdown. The exception is characters that have special meaning in Markdown (*, _, [, ]), which may need to be escaped with a backslash.
6. Code Blocks with Language Hints
HTML code blocks often indicate the language via a class: <pre><code class="language-python">. Good converters extract this class and produce a fenced block with the language identifier: ```python. If your converter does not handle this, you lose syntax highlighting metadata.
Converting Markdown Back to HTML
The reverse conversion -- Markdown to HTML -- is simpler and more reliable. Markdown is a subset of HTML's expressiveness, so every Markdown construct has an unambiguous HTML representation.
JavaScript (marked)
import { marked } from 'marked';
const md = '## Hello **World**\n\nA [link](https://example.com).';
const html = marked.parse(md);
// <h2>Hello <strong>World</strong></h2>
// <p>A <a href="https://example.com">link</a>.</p>
Python (markdown)
import markdown
md_text = "## Hello **World**\n\nA [link](https://example.com)."
html = markdown.markdown(md_text)
print(html)
For quick testing without writing code, use the QTool Markdown to HTML converter to see your Markdown rendered as HTML in real time. And if you want a full writing environment, the QTool Markdown Editor gives you a split-pane view with live preview as you type.
Best Practices for HTML-to-Markdown Conversion
1. Clean the HTML First
Before converting, strip out elements that have no Markdown equivalent: <script> tags, <style> blocks, tracking pixels, ad containers, and navigation chrome. The cleaner your input HTML, the cleaner your output Markdown. Use the QTool HTML Beautifier to reformat messy HTML so you can inspect and clean it before conversion.
2. Choose Your Markdown Flavor
Standard Markdown (CommonMark) does not support tables, task lists, or strikethrough. GitHub Flavored Markdown (GFM) adds these. Make sure your converter targets the flavor your rendering platform supports. Pandoc lets you specify the target with -t gfm, -t commonmark, or -t markdown_strict.
3. Validate the Output
Always render the converted Markdown and compare it visually against the original HTML. Automated conversion is imperfect. Check for broken links, missing images, flattened lists, and stripped formatting. The QTool Markdown Preview tool renders Markdown as HTML instantly so you can spot problems quickly.
4. Handle Images Separately
HTML-to-Markdown conversion changes image references from <img> tags to  syntax, but it does not download the images. If the image URLs point to the original server, they will break if the server goes down. For CMS migrations, download all images to a local assets directory and update the URLs in your Markdown files.
5. Preserve Metadata
HTML pages contain metadata in <title>, <meta> tags, and structured data that has no place in Markdown body content. If you are converting blog posts or documentation, extract this metadata into YAML front matter at the top of each Markdown file:
---
title: "How to Convert HTML to Markdown"
date: 2026-02-13
author: "Christian Bucher"
tags: ["html", "markdown", "conversion"]
---
# How to Convert HTML to Markdown
Article content starts here...
6. Test with Real Content
Do not test your conversion pipeline with simple, well-formed HTML. Test it with the messiest, most complex pages from your actual content. WYSIWYG editors produce surprisingly creative HTML. A converter that works on clean HTML may choke on real-world content from WordPress, Notion exports, or Google Docs HTML.
Convert Your HTML to Markdown Now
No sign-up, no data sent to servers, no ads. Paste your HTML and get clean Markdown output instantly.
Open HTML to Markdown ConverterFrequently Asked Questions
How do I convert HTML to Markdown?
The fastest way is to paste your HTML into a browser-based converter like QTool HTML to Markdown. It maps HTML tags to their Markdown equivalents instantly: headings become # symbols, bold becomes **, links become [text](url), and so on. For programmatic conversion, use libraries like Turndown (JavaScript), markdownify (Python), or Pandoc (command line).
Does Markdown support all HTML features?
No. Markdown covers common formatting like headings, bold, italic, links, images, lists, code blocks, and blockquotes. HTML features without a Markdown equivalent include tables with merged cells, colored text, embedded forms, iframes, and complex layouts. Most Markdown processors allow inline HTML as a fallback for unsupported features.
What is the best HTML to Markdown library for JavaScript?
Turndown is the most widely used JavaScript library for HTML-to-Markdown conversion. It parses HTML into a DOM tree and converts each element to its Markdown equivalent. It supports custom rules via plugins, handles edge cases like nested lists and code blocks, and works in both Node.js and the browser. Install it with npm install turndown.
Can I convert Markdown back to HTML?
Yes. Markdown-to-HTML conversion is simpler and more reliable than the reverse because Markdown has fewer features than HTML. Libraries like marked and markdown-it (JavaScript), Python-Markdown, and Pandoc all convert Markdown to clean HTML. You can use the free QTool Markdown to HTML converter to do this instantly in your browser.
Is it safe to convert HTML to Markdown online?
It is safe if the tool processes your HTML entirely in the browser without sending data to a server. QTool HTML to Markdown runs client-side using JavaScript, so your content never leaves your machine. You can verify this by checking the network tab in your browser developer tools. Avoid online converters that require you to upload files to their servers, especially if your HTML contains sensitive content.
Explore 269 Free Developer Tools
HTML to Markdown is just the start. QTool has free tools for JSON, CSS, regex, encoding, images, and much more. All browser-based, all private.
Browse All Free Tools