Table of contents
Markdown is the format of choice for documentation, README files, blog posts, and developer notes. But browsers do not render Markdown — they render HTML. At some point, every Markdown document needs to be converted to HTML for display, deployment, or publishing.
This guide explains exactly how Markdown-to-HTML conversion works, covers the full syntax mapping, and shows you how to handle edge cases like tables, code blocks, and custom extensions.
How Markdown-to-HTML conversion works
A Markdown parser reads plain text with Markdown syntax and outputs equivalent HTML. The process is:
- Tokenization: The parser scans the input and identifies Markdown elements (headings, paragraphs, lists, code blocks, etc.)
- Parsing: Each element is parsed according to the Markdown specification
- Rendering: Each parsed element is converted to its HTML equivalent
- Output: A complete HTML fragment (or document) is returned
The conversion is deterministic — the same Markdown input always produces the same HTML output for a given parser and specification.
Complete Markdown to HTML syntax reference
Headings
Markdown uses # symbols to mark headings. The number of # symbols corresponds to the heading level:
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
Converts to:
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
Paragraphs
Any block of text separated by a blank line becomes a paragraph:
This is the first paragraph.
This is the second paragraph.
Converts to:
<p>This is the first paragraph.</p>
<p>This is the second paragraph.</p>
A single line break within a paragraph does not create a new paragraph. To force a line break (<br>) without starting a new paragraph, end the line with two spaces.
Emphasis
**bold text**
*italic text*
***bold and italic***
~~strikethrough~~
Converts to:
<strong>bold text</strong>
<em>italic text</em>
<strong><em>bold and italic</em></strong>
<del>strikethrough</del>
Note: Strikethrough (~~) is a GitHub Flavored Markdown (GFM) extension and is not in the CommonMark standard.
Lists
Unordered list:
- Item one
- Item two
- Nested item
- Item three
Converts to:
<ul>
<li>Item one</li>
<li>Item two
<ul>
<li>Nested item</li>
</ul>
</li>
<li>Item three</li>
</ul>
Ordered list:
1. First item
2. Second item
3. Third item
Converts to:
<ol>
<li>First item</li>
<li>Second item</li>
<li>Third item</li>
</ol>
Links and images
[Link text](https://example.com)
[Link with title](https://example.com "My title")


Converts to:
<a href="https://example.com">Link text</a>
<a href="https://example.com" title="My title">Link with title</a>
<img src="image.png" alt="Alt text">
<img src="image.png" alt="Alt text" title="Image title">
Code
Inline code uses backticks:
Use the `console.log()` function.
Converts to:
Use the <code>console.log()</code> function.
Fenced code blocks use triple backticks with an optional language identifier:
```javascript
const greeting = 'Hello, world!';
console.log(greeting);
```
Converts to:
<pre><code class="language-javascript">const greeting = 'Hello, world!';
console.log(greeting);
</code></pre>
The language-javascript class is added by the parser and can be used by syntax highlighting libraries like Prism.js or highlight.js.
Blockquotes
> This is a blockquote.
> It can span multiple lines.
Converts to:
<blockquote>
<p>This is a blockquote. It can span multiple lines.</p>
</blockquote>
Horizontal rule
---
Converts to:
<hr>
Tables (GFM extension)
Tables are a GitHub Flavored Markdown extension:
| Column 1 | Column 2 | Column 3 |
|----------|----------|----------|
| Cell 1 | Cell 2 | Cell 3 |
| Cell 4 | Cell 5 | Cell 6 |
Converts to:
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td>Cell 4</td>
<td>Cell 5</td>
<td>Cell 6</td>
</tr>
</tbody>
</table>
Column alignment can be specified with colons in the separator row:
:---— left align---:— right align:---:— center align
Task lists (GFM extension)
- [x] Completed task
- [ ] Incomplete task
- [x] Another completed task
Converts to:
<ul>
<li><input type="checkbox" checked disabled> Completed task</li>
<li><input type="checkbox" disabled> Incomplete task</li>
<li><input type="checkbox" checked disabled> Another completed task</li>
</ul>
Markdown flavors: which parser to use
Not all Markdown is the same. Different platforms use different Markdown specifications:
| Platform | Markdown flavor |
|---|---|
| GitHub | GitHub Flavored Markdown (GFM) |
| CommonMark | |
| Stack Overflow | CommonMark |
| Jekyll | Kramdown |
| Hugo | Goldmark (CommonMark) |
| Notion | Proprietary subset |
| Obsidian | CommonMark + extensions |
When converting Markdown to HTML, use the parser that matches where your Markdown was written. Converting GFM content with a CommonMark-only parser will drop tables and task lists silently — they appear to disappear.
Converting Markdown to HTML in different environments
In a browser (JavaScript)
The most popular JavaScript Markdown parsers are:
- marked.js — fast, widely used, supports GFM
- markdown-it — highly configurable, plugin ecosystem
- showdown — older but still used, supports extensions
Example with marked.js:
import { marked } from 'marked';
const markdown = '# Hello\n\nThis is **bold** text.';
const html = marked(markdown);
// <h1>Hello</h1><p>This is <strong>bold</strong> text.</p>
In Node.js / server-side
The same JavaScript parsers work in Node.js. For more control over the output, use markdown-it with custom renderers or plugins.
In Python
Popular Python Markdown parsers:
- markdown — the reference implementation, supports extensions
- mistune — fast, zero dependencies
- python-markdown2 — compatible with most GFM features
import markdown
text = '# Hello\n\nThis is **bold** text.'
html = markdown.markdown(text)
In static site generators
Jekyll, Hugo, Eleventy, and Next.js all handle Markdown-to-HTML conversion automatically as part of their build process. You write .md files; the generator converts them to HTML pages at build time.
Working with the output HTML
Once you have the HTML output from a Markdown conversion, you may need to:
Format it for readability: Raw Markdown-to-HTML output is often a single unindented block. The FixTools HTML Formatter adds proper indentation and line breaks, making the structure easy to read and debug.
Validate the HTML: After conversion, verify the output is valid HTML with no unclosed tags or malformed attributes. The HTML Validator checks your output and reports any issues.
Minify for production: If you are embedding the HTML in a web application or template, the HTML Minifier removes unnecessary whitespace and comments to reduce file size.
Embedding raw HTML in Markdown
Most Markdown parsers pass raw HTML through unchanged when it appears in a Markdown document. This lets you use HTML elements that have no Markdown equivalent:
This paragraph is normal Markdown.
<div class="callout">
This is a custom callout box using raw HTML.
</div>
Back to normal Markdown.
The <div class="callout"> block passes through to the HTML output without modification. This is useful for custom containers, spans with classes, embedded iframes, or any HTML element that Markdown cannot represent.
Security: sanitizing Markdown output
When converting user-submitted Markdown to HTML, always sanitize the output. Markdown parsers that allow raw HTML pass any HTML through — including <script> tags and event handlers. This creates an XSS (Cross-Site Scripting) vulnerability.
Use a sanitization library after conversion:
- DOMPurify (browser JavaScript)
- sanitize-html (Node.js)
- bleach (Python)
These libraries strip dangerous HTML while preserving safe formatting. Never render unsanitized user-provided Markdown as HTML without sanitization.
Convert and validate your HTML output
After converting Markdown to HTML, paste the output into the FixTools HTML Formatter to add clean indentation and make the structure readable. Then use the HTML Validator to confirm there are no structural errors before using it in production.
For publishing to a live page, the HTML Minifier produces the smallest possible file by removing whitespace and redundant attributes without changing how the browser renders the content.
Try it free — right in your browser
No sign-up, no uploads. Your data stays private on your device.
Frequently asked questions
6 questions answered
QWhat is Markdown and why is it used instead of HTML?
Markdown is a lightweight text formatting syntax created by John Gruber in 2004. It uses simple characters like # for headings, ** for bold, and - for lists, making content easy to read and write as plain text. HTML achieves the same formatting but is more verbose and harder to read in raw form. Markdown is used in documentation, README files, blog platforms, and content management systems because writers can focus on content without managing HTML tags.
QIs Markdown-to-HTML conversion lossless?
Standard Markdown converts losslessly to HTML — every Markdown element has a defined HTML equivalent. Headings become h1–h6 tags, bold becomes strong, italic becomes em, links become anchor tags, and so on. The only exception is features that vary by Markdown flavor: GitHub Flavored Markdown supports tables and task lists while standard CommonMark does not. If you use GFM-specific syntax and convert with a standard parser, those elements may not convert correctly.
QCan I convert HTML back to Markdown?
Yes, reverse conversion (HTML to Markdown) is possible, but it is lossy. HTML supports inline styles, custom classes, and complex attributes that have no Markdown equivalent. A reverse converter strips those or represents them as raw HTML inline. For simple HTML with standard formatting, the conversion is fairly clean. For HTML with heavy styling or complex structure, the output Markdown will need manual cleanup.
QWhat Markdown elements do not convert to HTML automatically?
Custom Markdown extensions vary by parser. Standard CommonMark does not include syntax for tables, footnotes, definition lists, or task checkboxes. These are supported in GitHub Flavored Markdown (GFM) and other extended flavors. If your content uses these elements and your target platform uses a different Markdown parser, the output HTML may be missing those features or render them as plain text.
QHow do I include raw HTML inside Markdown?
Most Markdown parsers allow raw HTML to be embedded directly in the document. Just write the HTML tags inline and the parser passes them through unchanged. For example, you can add a <div class="note"> wrapper around a paragraph, or use <br> for a line break without starting a new paragraph. The raw HTML is preserved in the output. This is useful for elements Markdown cannot express, like custom containers or inline spans with classes.
QWhat is the difference between CommonMark, GFM, and other Markdown flavors?
CommonMark is a standardized Markdown specification that resolves ambiguities in the original spec. GitHub Flavored Markdown (GFM) is CommonMark plus extensions: tables, task lists, strikethrough, and auto-linking of URLs. MultiMarkdown adds footnotes, definition lists, and math. Pandoc Markdown is highly extensible and supports academic citation formats. When converting Markdown to HTML, the flavor matters — use the parser that matches the syntax your content was written in.
O. Kimani
Software Developer & Founder, FixTools
Building FixTools — a single destination for free, browser-based productivity tools. Every tool runs client-side: your files never leave your device.
About the authorRelated articles
How to Minify HTML, CSS, and JavaScript Safely
Shrink your code for faster pages without breaking your site. What minification actually does, what to watch out for, and free tools to do it right.
Read articleDeveloper & WebBest Free JSON Formatter and Validator Online (2026)
Format messy JSON instantly and catch syntax errors before they break your app. Free browser-based JSON formatter and validator. No signup, no install.
Read article