Skip to the tool
makeshortwork.com Markdown to HTML

Markdown to HTML Converter

Paste Markdown, get HTML and a live preview side by side. Embedded HTML is sanitized by default and nothing ever leaves this tab.

Paste Markdown, drop a .md file, or

Rendered from the sanitized HTML.

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.

DialectAddsWhere 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 &lt;, and every bare & becomes &amp;. 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 &amp; turn into &amp;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, &amp; 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:

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.

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.

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:

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&#58;, java\tscript: and &#106;avascript: 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.