Markdown Editor & Preview

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
Preview

1 Syntax you will use most

Text

  • # H1 through ###### H6
  • **bold** and *italic*
  • ~~strikethrough~~
  • `inline code`
  • > blockquote
  • --- horizontal rule

Blocks

  • - item, or 1. item
  • - [ ] and - [x] task lists
  • [label](https://url)
  • ![alt](image.png)
  • | a | b | with |---|---|
  • Fenced code with three backticks

2 The parts people get wrong

Line breaks

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.

Nested lists

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.

Tables need a separator

A table needs a |---|---| row directly under the header. Without it, the parser renders a paragraph full of pipes.

Underscores inside words

Some parsers turn snake_case_names into italics. Wrap identifiers in backticks so they render as code.

3 Sanitized, then rendered

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.

How to use the Markdown Editor & Preview tool

  1. Type Markdown in the left panel. The right panel updates as you type.
  2. Switch the Right panel dropdown from Preview to HTML source to see the markup instead of the rendering.
  3. Click Copy HTML to put the sanitized markup on the clipboard, or Download .md to save the Markdown itself.
  4. Click Upload .md to load an existing file from disk.
  5. Click Dummy Data for a sample document with a table, a task list and a fenced code block, so you can see how each feature renders.

How to render Markdown to HTML in JavaScript, PHP and Python

JavaScript / Node.js

// 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

<?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.

Python

# 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"]}))

Common errors and how to fix them

Single line breaks disappear
This is correct CommonMark behavior: one newline inside a paragraph is a soft break. End the line with two spaces or a backslash, or turn on the breaks option in your parser if you want every newline to become a line break.
The table renders as a paragraph full of pipes
The |---|---| separator row under the header is missing, or the table is not preceded by a blank line. Tables are also a GitHub extension, so the parser needs GFM enabled.
A nested list renders flat
The indentation does not reach the parent's content column. Under a dash, indent by two spaces; under 1., by three. Mixing tabs and spaces in the same list is the usual cause.
snake_case_words turn into italics
Underscores inside a word are emphasis in some parsers. Wrap the identifier in backticks, or escape the underscores.
Raw HTML in the Markdown does not appear
The sanitizer removed it. This tool strips scripts, event handlers and javascript: URLs on purpose. In your own code, check whether the parser escapes HTML input, which is the right default for user-submitted content.

Good to know

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.

Specifications and references

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.

Frequently Asked Questions

Which Markdown dialect is supported?

GitHub Flavored Markdown, rendered by the marked library: CommonMark plus tables, task lists, strikethrough, autolinks and fenced code blocks with a language tag.

Can I get the HTML out?

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.

Is raw HTML inside my Markdown allowed?

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.

Does the preview match GitHub exactly?

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.

Is my document saved anywhere?

No. The text lives in the textarea and disappears when you close the tab. Click Download .md to keep a copy.

Related

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.

More Text & Content Tools

Browse all text & content tools

Copied to clipboard!