Markdown Editor and Previewer
Write markdown, watch it render, and take the HTML. Tables, task lists and fenced code included; pasted HTML and javascript: links are not.
Enable JavaScript to write your own; the preview below is the example.
Nothing is uploaded. The rendering happens in this tab.
A fragment is the content on its own. A document adds the doctype, head and body around it.
Used only by the document output.
107 words · 576 characters · about 1 minute to read
Release notes
A paragraph with bold, italic, code and a link.
What changed
- Tables, task lists and fenced code
- Heading ids, so every section can be linked to
- HTML in the input is escaped, never rendered
| Setting | Default | Notes |
|---|---|---|
cache | on | per site |
debug | off | logs to file |
<?php
add_filter( 'the_content', 'my_plugin_render' );
Pasted HTML is shown as text. A preview that renders whatever is pasted into it is a preview that runs whatever is pasted into it.
<h1 id="release-notes">Release notes</h1>
<p>A paragraph with <strong>bold</strong>, <em>italic</em>, <code>code</code> and a <a href="https://example.com">link</a>.</p>
<h2 id="what-changed">What changed</h2>
<ul>
<li>Tables, task lists and fenced code</li>
<li>Heading ids, so every section can be linked to</li>
<li><input type="checkbox" checked disabled /> HTML in the input is escaped, never rendered</li>
</ul>
<table>
<thead>
<tr><th style="text-align: left">Setting</th><th style="text-align: center">Default</th><th style="text-align: right">Notes</th></tr>
</thead>
<tbody>
<tr><td style="text-align: left"><code>cache</code></td><td style="text-align: center">on</td><td style="text-align: right">per site</td></tr>
<tr><td style="text-align: left"><code>debug</code></td><td style="text-align: center">off</td><td style="text-align: right">logs to file</td></tr>
</tbody>
</table>
<pre><code class="language-php"><?php
add_filter( 'the_content', 'my_plugin_render' );</code></pre>
<blockquote>
<p>Pasted HTML is shown as text. A preview that renders whatever is pasted into
it is a preview that runs whatever is pasted into it.</p>
</blockquote>
Type markdown on the left, watch it render on the right, take the HTML at the bottom. Tables, task lists, fenced code with a language class, and an id on every heading so sections can be linked to.
One thing this deliberately does not do: render HTML you paste in. It is escaped and shown as text. A preview that renders whatever is pasted into it is a preview that runs whatever is pasted into it, and no editor needs that to be useful.
How to use
- Write or paste markdown. The preview keeps up as you type; nothing is uploaded and nothing is saved.
- Leave Add ids to headings on if the HTML is going into a page with a
table of contents. Ids come from the heading text, and a repeated heading
gets
-2,-3after it. - Turn on Every newline is a line break if the text was written somewhere that works that way, such as a chat app or an issue tracker. Markdown’s own rule is that a single newline is a space and a real break needs two trailing spaces.
- Switch the output to document to get a standalone file with a doctype,
<head>and<body>around the content. - Copy the HTML, or download it.
Example
This markdown:
## Settings
| Setting | Default | Notes |
| :------ | :-----: | ----: |
| `cache` | on | per site |
- [x] Written
- [ ] Reviewed
comes out as:
<h2 id="settings">Settings</h2>
<table>
<thead>
<tr><th style="text-align: left">Setting</th><th style="text-align: center">Default</th><th style="text-align: right">Notes</th></tr>
</thead>
<tbody>
<tr><td style="text-align: left"><code>cache</code></td><td style="text-align: center">on</td><td style="text-align: right">per site</td></tr>
</tbody>
</table>
<ul>
<li><input type="checkbox" checked disabled /> Written</li>
<li><input type="checkbox" disabled /> Reviewed</li>
</ul>
The alignments come from the colons in the delimiter row, the checkboxes are
disabled so the rendered page cannot be half-ticked by a visitor, and cache
became a <code> element rather than a styled span.
Pitfalls
A link to javascript: is dropped. So is data:, and anything else whose
scheme is not http, https, mailto or tel. The markdown is shown as written
instead of silently becoming plain text, so it is obvious the link was refused
rather than mistyped.
Nesting is one level deep. Indent a list item by two or more spaces and it nests; indent further and it still nests once. Deeply nested lists are rare in the writing this is for, and the alternative is a parser three times the size.
A pipe in a paragraph is not a table. A table needs the delimiter row
(| --- |) directly under the header row. Without it, the pipes stay pipes.
Underscores inside words are left alone. snake_case_name stays
snake_case_name; only _word_ with a boundary in front becomes italic. Same
for 2 * 3 * 4, which is arithmetic, not emphasis.
Setext headings are not supported. Title with ==== under it stays a
paragraph followed by a rule. Use #.
Compatibility
The subset follows CommonMark for the constructs it covers, plus GitHub’s tables and task lists. What it leaves out is reference links, setext headings, footnotes and raw HTML.
The output is plain HTML with no classes except the language-* on fenced code,
which is what Prism and highlight.js look for. It pastes into the WordPress block
editor: use the code editor view (Ctrl or Cmd, Shift and Alt, then M) and the
blocks are recognised on switching back.
Rendering happens in the browser, in any version that ships the Interactivity API runtime WordPress 6.5 introduced. Without JavaScript the page still shows the example rendered, because the same renderer runs on the server.
Frequently asked questions
Can I paste HTML and have it kept?
< in the input becomes <. If you need HTML in the output,
write it after copying, or put it through the HTML formatter instead.Why do my headings have ids I did not write?
Does the preview match what WordPress will show?
How large a document can I paste?
What happens to a code fence I never closed?
<pre> block containing the rest of the text.