What this converter actually does
Markdown looks like the easiest format in the world to convert. Replace hashes with headings, asterisks with emphasis, done. That impression survives exactly until the first real document — a README with a code sample, a runbook with nested steps, a changelog written by somebody who likes underscores in variable names.
The parser here follows CommonMark, the specification written after years of the original Markdown's ambiguities producing incompatible output, plus the GitHub Flavored Markdown extensions you can switch on and off: tables, strikethrough and task lists. It runs entirely in this tab, in about six hundred lines of JavaScript you can read in the page source, with no library behind it and no request to any server.
Four things separate a converter you can trust from one that quietly ruins documents: what it does with angle brackets in your prose, what it does with the contents of a code block, what it does with a link whose URL is hostile, and whether it understands indentation well enough to keep a nested list nested. Everything below is about those four.
Why the same Markdown renders three different ways
People assume Markdown is a standard. It is not one standard; it is a family. John Gruber's original 2004 implementation was a Perl script with no formal grammar, and its behaviour in ambiguous cases was simply whatever the script happened to do. Twenty years of tools then copied different parts of it.
| Dialect | Adds | Where you meet it |
|---|---|---|
| CommonMark | A precise spec with a test suite; defines emphasis, lists and HTML blocks unambiguously | Discourse, Reddit, Stack Overflow, most static site generators |
| GitHub Flavored | Tables, strikethrough, task lists, autolinked bare URLs, footnotes | GitHub, GitLab, most developer documentation |
| MultiMarkdown / Pandoc | Citations, definition lists, metadata blocks, math | Academic writing, book pipelines |
| App dialects | Notion, Slack, Discord and Obsidian each support a subset with their own additions | Anywhere the Markdown never leaves the app |
The practical consequence is that a document that renders beautifully in a GitHub issue can fall apart in your blog engine. Bare URLs stop becoming links. Footnotes turn into literal square brackets. A table becomes a paragraph full of pipe characters. None of that is a bug in either tool — they implement different dialects. When output here differs from what you saw somewhere else, the extension toggles are the first place to look, and switching tables or task lists off will usually reproduce the other tool's behaviour exactly.
Escaping: the part that looks cosmetic and is not
Write if a < b && c in a paragraph and a naive converter will
emit those characters unchanged. The browser then reads < b &&
as the start of a tag, swallows text until it finds a >, and part of
your sentence disappears. Users report it as "the page ate my text".
The fix is that every < that is not part of real markup becomes
<, and every bare & becomes
&. That is not only about appearances. Text that reaches a page
unescaped is the definition of an injection point, and Markdown documents very often
come from somebody else — a pull request description, a support ticket, a comment.
One subtlety: an ampersand that is already part of a valid HTML entity is left alone.
Without that rule, someone documenting HTML watches & turn into
&amp; on every conversion, which is the most common complaint
about over-eager escaping.
Code blocks are literal, and that is the whole point
Inside a fenced block or a pair of backticks, nothing is Markdown. Asterisks stay
asterisks, brackets stay brackets, and every angle bracket and ampersand is escaped so
the sample survives to the screen. A converter that skips this step renders your
example <div class="card"> as an actual div: the code sample
vanishes and takes the surrounding layout with it.
Note that entities are handled differently here than in prose. In a code block,
& is the literal text the reader must see, so it is escaped again
rather than preserved. Prose and code genuinely need opposite rules, and mixing them
up is how documentation about HTML ends up destroying itself.
Embedded HTML: useful, then dangerous
Markdown deliberately allows raw HTML, and for good reasons. There is no Markdown
syntax for a collapsible section, a keyboard key, a subscript, an image with a fixed
width, or a table cell that spans two columns. Documentation writers reach for
<details>, <kbd>, <sub> and
plain <img> constantly, and a converter that escapes all of it is
useless for real README files.
The same door lets everything else in. <script>,
<iframe>, an onerror attribute on a broken image, a
<form> that posts credentials somewhere else — all of it is valid
Markdown, because Markdown's rule is simply to pass HTML through. If you are
converting a document you did not write and publishing the result, you are publishing
whatever was in it.
So the tool offers three modes and defaults to the careful one:
- Sanitize — tags and attributes are checked against an allowlist. Useful markup survives; anything outside the list becomes visible escaped text rather than disappearing silently.
- Escape as text — all raw HTML is shown literally. This is the right mode when the document is about HTML and you want the tags on the page.
- Allow raw — nothing is filtered. Only for documents you wrote yourself, and even then the preview on this page stays sanitized.
How the sanitizer decides
Every decision is an allowlist, never a blocklist. A blocklist fails
by omission: nobody remembers vbscript:, nobody remembers
<object>, and nobody can list the attributes a future browser will
add. An allowlist fails safely — the worst case is that an exotic tag shows up as text.
- Tags. Roughly seventy structural and inline elements are kept.
Everything else is escaped, so you can see it was removed. Elements whose content is
code rather than text —
script,style,iframe,svg— are escaped together with their body, because dropping only the opening tag would leave the code loose in the document. - Attributes. Also an allowlist, which is what neutralises
<img src=x onerror=alert(1)>. Theimgelement is legitimate and stays;onerroris simply not on the list, and neither is any otheron*handler, present or future.styleis dropped too, since CSS can reposition an element over a real button. - URLs.
href,srcandcitego through a scheme check. Control characters and invisible Unicode are stripped and entities decoded first, becausejava script:andjavascript:both navigate as JavaScript. A blocked URL loses the attribute; the link text stays visible and the warning strip names what was removed.
You can watch all of this work: the XSS demo button loads a document containing the standard payloads, and the result shows what survived and what did not.
Underscores, asterisks and snake_case
snake_case_name must not turn into italics. It is a small detail with a
large blast radius, because it appears in every technical document ever written, and
the naive fix — matching pairs of underscores with a regular expression — mangles all
of them.
CommonMark solves it by looking at what surrounds each run of delimiters. A run of
underscores with a letter on both sides can neither open nor close emphasis, which is
exactly the snake_case_name case. Asterisks follow a looser rule on
purpose, so snake*case*name does emphasise. The two characters
are not interchangeable, whatever the cheat sheets say, and this converter implements
the real rule rather than a regular expression.
Nested lists and the indentation rule
Nested lists are the hardest part of any Markdown parser, and the place where quick implementations flatten everything into a single level. The rule is not about the marker; it is about the column where the item's content starts. A dash followed by one space puts content in column two, so a line indented two spaces or more belongs to that item, and a marker found there starts a nested list. Indent by one space instead and the line is a continuation of the same paragraph.
This is why a list that looks fine in your editor collapses somewhere else: the two
tools disagree about how a tab expands, or about how much indentation an ordered
marker like 10. demands. Tabs are expanded to four-column stops here,
which is the CommonMark rule, and both levels of nesting are handled including mixed
bullet and ordered lists.
Link reference definitions
Real documents rarely put long URLs inline. They write [the spec][cm] and
collect [cm]: https://commonmark.org at the bottom, which keeps
paragraphs readable and lets one URL serve several mentions. Converters that ignore
reference definitions produce two visible failures at once: the links do not resolve,
and the definition block shows up as a stray paragraph of brackets at the end of the
page. Labels here are matched case-insensitively with whitespace collapsed, titles are
supported, and the definitions are removed from the output — but only when they stand
alone, since a definition cannot interrupt a paragraph.
Pasting into WordPress, a CMS or an email
Where the HTML is going changes which output style you want.
- WordPress. Use the fragment, and paste it into a Custom HTML block rather than the visual editor, which rewrites markup it does not recognise and sometimes strips attributes. If you are on the classic editor, switch to the Text tab first.
- A CMS or newsletter tool. Fragment again. Most editors expect body
markup and will escape or discard a doctype and a
<head>. - Email. Fragment, and expect the recipient's client to apply its own
defaults. Gmail strips
<style>blocks, Outlook renders with an engine that predates most of CSS, and only inline styles survive everywhere. Markdown converts to structure, not to a design. - A standalone file. Choose the full document option. You get a doctype, a charset declaration, a viewport meta tag and a small readable stylesheet, and the title is taken from your first heading.
What is lost in the conversion
Being honest about the ceiling saves you from debugging the wrong thing. Markdown carries structure — headings, lists, emphasis, links, code — and nothing else. It has no concept of fonts, colours, columns, page breaks or spacing. Converting it produces semantic HTML that a stylesheet then has to dress.
Some specifics worth knowing before you paste:
- Front matter — the YAML block between
---lines that static site generators read is not part of Markdown. It converts as content, so remove it first. - Footnotes and definition lists are GitHub and Pandoc extensions, not CommonMark, and are not implemented here.
- Math in
$…$delimiters is a MathJax or KaTeX convention layered on top of Markdown; it passes through as literal text. - Syntax highlighting is not applied. The language from the fence
becomes
class="language-js", which is what Prism and highlight.js read, but colouring happens in whatever renders the page. - Images are links, not files. A relative path such as
./diagram.pngis preserved exactly, and it will only resolve where that file actually exists.
Privacy
Every step happens in this tab: reading the file, parsing, sanitizing, rendering the preview. Nothing is uploaded, nothing is stored, and there is no account or usage limit. That matters more for Markdown than for most formats, because the Markdown files people convert are drafts, internal documentation, incident write-ups and release notes that have not been announced yet. You can verify the claim two ways: open your browser's network tab and watch nothing happen, or disconnect entirely and convert anyway.
Frequently asked questions
Is my document uploaded anywhere?
No. The parser is plain JavaScript that runs inside this tab. Nothing is sent to a server, nothing is logged, and there is no account. You can turn off your network connection and keep converting, which matters because Markdown files are usually drafts, internal runbooks, release notes under embargo and documentation that has not shipped yet.
Does it stop XSS in Markdown, like [click](javascript:alert(1))?
Yes, and that link is worth understanding: it needs no embedded HTML at all, only ordinary link syntax. Every URL is checked against an allowlist of schemes after control characters and whitespace are stripped and HTML entities are decoded, because javascript:, java\tscript: and javascript: all navigate the same way. Anything outside the allowlist loses its href instead of being deleted, so you can see what was blocked. data: URLs are refused in full, including for images, because data:image/svg+xml is both an image and a scriptable document.
What happens to HTML I wrote inside the Markdown?
That is your choice, and the default is the safe one. Sanitize keeps useful markup such as <kbd>, <details>, <sub> and <img> but drops every tag and attribute outside the allowlist, which removes all on* event handlers by construction. Escape turns raw HTML into visible text, which is what you want when you are writing about HTML. Allow raw passes everything through untouched — use it only for documents you wrote yourself. Even then the on-page preview stays sanitized, because this page never executes markup you paste into it.
Why does my Markdown look different here than on GitHub or Notion?
Because there is no single Markdown. This converter follows CommonMark for structure plus the GitHub Flavored Markdown extensions you can toggle: tables, strikethrough and task lists. GitHub adds autolinking of bare URLs and its own footnote syntax; Notion, Slack, Discord and Reddit each use a different dialect again, and older tools built on the original 2004 Perl script disagree with all of them on nested lists and emphasis. If output differs, it is almost always one of those extensions rather than a bug in the core parser.
Can I paste the result straight into WordPress or an email?
Yes, with one caveat each. WordPress works best when you paste the HTML fragment into a Custom HTML block; the visual editor rewrites markup it does not recognise. Email clients ignore most of a stylesheet and many ignore <style> blocks entirely, so a fragment pasted into an email will render with the client's defaults — readable, but unstyled. Choose the full HTML document option when the file has to stand on its own in a browser.
Are code blocks safe from Markdown processing?
Yes. Anything inside a fenced block or backticks is treated as literal text: no emphasis, no links, no HTML, and every angle bracket and ampersand is escaped. This is the single most common failure in home-made converters — a code sample containing a <div> gets rendered as an actual div, and the example disappears from the page.