Write Markdown on the left, watch it render on the right, and copy the HTML when you are done. Tables, task lists and fenced code blocks all work, and DOMPurify sanitizes the output before it reaches the preview.
Markdown joins lines that are separated by a single newline into one paragraph. End a line with two spaces to force a line break, or leave a blank line to start a new paragraph.
Indent a child item to line up with the parent's text: two spaces under a dash, three under 1. followed by a space. Mixing tabs and spaces is the usual reason a nested list renders flat.
A table needs a |---|---| row directly under the header. Without it, the parser renders a paragraph full of pipes.
Some parsers turn snake_case_names into italics. Wrap identifiers in backticks so they render as code.
Markdown allows raw HTML, so a Markdown document from an untrusted source is as dangerous as untrusted HTML. Here, marked renders the Markdown and DOMPurify cleans the result before it reaches the preview, which removes script tags, inline event handlers and javascript: URLs. Copy HTML gives you that sanitized version.
Sanitize user-submitted Markdown after you render it.
The CommonMark spec treats raw HTML as valid content, so marked
passes it through by default. markdown-it escapes it unless you
set html: true. Whenever raw HTML is allowed, run the
rendered output through DOMPurify or your language's equivalent
before you store or display it.
// npm i marked dompurify jsdom
const { marked } = require("marked");
const createDOMPurify = require("dompurify");
const { JSDOM } = require("jsdom");
const DOMPurify = createDOMPurify(new JSDOM("").window);
const md = "# Title\n\nSome **bold** text and a [link](https://example.com).";
const dirty = marked.parse(md, { gfm: true });
const clean = DOMPurify.sanitize(dirty);
console.log(clean);
// Markdown allows raw HTML. If the source is user input,
// sanitizing afterwards is not optional. <?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', // do not trust raw HTML in the source
'allow_unsafe_links' => false, // no javascript: hrefs
]);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new GithubFlavoredMarkdownExtension());
$converter = new MarkdownConverter($environment);
echo $converter->convert("# Title\n\nTables and task lists included."); When the Markdown comes from users, set html_input to escape. It turns any raw HTML in the source into visible text instead of markup.
# pip install markdown-it-py bleach
from markdown_it import MarkdownIt
import bleach
md = MarkdownIt("commonmark").enable("table").enable("strikethrough")
html = md.render("# Title\n\n| a | b |\n|---|---|\n| 1 | 2 |")
ALLOWED = ["p", "h1", "h2", "h3", "strong", "em", "a", "code", "pre",
"ul", "ol", "li", "table", "thead", "tbody", "tr", "th", "td",
"blockquote", "hr", "br", "del"]
print(bleach.clean(html, tags=ALLOWED, attributes={"a": ["href", "title"]})) CommonMark is the spec that settled most of the ambiguity in John Gruber's original 2004 description. GitHub Flavored Markdown (GFM) is CommonMark plus tables, task lists, strikethrough and autolinks, and it is what most tools mean by Markdown today. The differences show up when a document moves between tools. For example, footnotes, definition lists and front matter are extensions that some parsers support and others print as plain text.
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.
GitHub Flavored Markdown, rendered by the marked library: CommonMark plus tables, task lists, strikethrough, autolinks and fenced code blocks with a language tag.
Yes. Switch the Right panel dropdown from Preview to HTML source to read the markup, and click Copy HTML to put it on the clipboard. It is plain HTML with no wrapper classes, so it drops into any template. Download .md saves the Markdown source, not the HTML.
It renders, but DOMPurify sanitizes it first. Script tags, inline event handlers and javascript: URLs are stripped before anything reaches the preview or the copied HTML.
The structure matches and the styling does not. GitHub applies its own stylesheet and syntax highlighting to the same kind of HTML, so headings and code blocks look different here. GitHub-only features such as @mentions, issue links and alert blocks are not rendered.
No. The text lives in the textarea and disappears when you close the tab. Click Download .md to keep a copy.
The HTML that comes out can be tidied with the HTML formatter. To check the length of a draft, the word counter has the numbers, and the diff checker shows what changed between two versions.