Convert Markdown to clean, sanitized HTML. Tables, task lists, strikethrough and fenced code all work, and the output uses plain semantic elements with no classes attached.
## Release notes
Shipped **2.4.0** on 10 September.
- [x] Store credit at checkout
- [ ] Partial refunds
| Change | Impact |
| ------ | ------ |
| New pricing API | breaking |
> Upgrade before the 30th. <h2>Release notes</h2>
<p>Shipped <strong>2.4.0</strong> on 10 September.</p>
<ul>
<li><input checked disabled type="checkbox"> Store credit at checkout</li>
<li><input disabled type="checkbox"> Partial refunds</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>
Markdown lets raw HTML through by design, so a document from an
untrusted source carries the same risk as untrusted HTML. This
page runs the rendered HTML through DOMPurify, which removes
script tags, inline event handlers such as onerror,
and javascript: URLs before the output appears.
Sanitize user-submitted Markdown in your own code too. Marked, markdown-it and league/commonmark all pass raw HTML through by default, because the CommonMark spec allows it. If you render user Markdown on a server, sanitize the result or set the parser's own escape option. Without that step, a comment box becomes a stored XSS (a script saved in your database and served to every visitor).
Indents the markup instead of emitting one line per block. The browser renders both the same way, but indented HTML is easier to review and diff.
CommonMark joins a single newline into the same paragraph, while GitHub comments turn it into a line break. Turn this on to get the GitHub-comment behavior.
Markdown has no syntax for classes, so you get semantic elements such as h2, table and blockquote. Style them from your own stylesheet.
The Markdown editor renders side by side as you type. Use this page for a one-off conversion.
// npm i marked dompurify jsdom
const { marked } = require("marked");
const createDOMPurify = require("dompurify");
const { JSDOM } = require("jsdom");
const DOMPurify = createDOMPurify(new JSDOM("").window);
const html = DOMPurify.sanitize(
marked.parse(userInput, { gfm: true, breaks: false }),
);
// Markdown allows raw HTML through by design. If userInput came from a
// person, that sanitize call is the whole security boundary. <?php
// composer require league/commonmark
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
use League\CommonMark\MarkdownConverter;
$environment = new Environment([
'html_input' => 'escape', // the important line for user content
'allow_unsafe_links' => false,
]);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new GithubFlavoredMarkdownExtension());
echo (new MarkdownConverter($environment))->convert($userInput); # pip install markdown-it-py bleach
from markdown_it import MarkdownIt
import bleach
md = MarkdownIt("commonmark").enable(["table", "strikethrough"])
html = md.render(user_input)
ALLOWED = ["p", "h1", "h2", "h3", "h4", "strong", "em", "del", "a", "code",
"pre", "ul", "ol", "li", "blockquote", "hr", "br",
"table", "thead", "tbody", "tr", "th", "td"]
safe = bleach.clean(html, tags=ALLOWED, attributes={"a": ["href", "title"]}) CommonMark settled most of the ambiguity in the original 2004 description, and GitHub Flavored Markdown is CommonMark plus tables, task lists, strikethrough and autolinks. Footnotes, definition lists and YAML front matter are extensions that some parsers support and others ignore without an error. That is why the same document can render correctly in one tool and break in the next.
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.
CommonMark plus the common GitHub extensions: tables, task lists, strikethrough and fenced code blocks with a language tag.
Yes. Markdown lets raw HTML pass straight through, so the rendered output goes through DOMPurify, which removes script tags, inline event handlers and javascript: URLs before you see it.
Turn on Format output and the markup comes out indented instead of as one long line per block. The browser renders both the same way; the indented version is easier to read and diff.
Markdown has no syntax for classes. You get semantic elements such as h2, table and blockquote, and you style them from your own stylesheet.
Use the Markdown editor, which renders side by side as you type. This page is for a one-off conversion where you only need the HTML.
HTML to Markdown does the reverse. For a side-by-side preview while you write, use the Markdown editor, and to tidy the resulting markup, the HTML formatter.