Paste a document and get the HTML for it, or paste a page and get the Markdown back. Both directions run in this tab: the conversion is a function of the text, so nothing is uploaded and there is no endpoint behind the page that could accept a draft even if something tried to send one. What makes the page worth reading is everything printed beside the answer - the outline of the document, every link with the scheme it uses, the elements Markdown cannot carry, the syntax this page does not implement, and the round trip, which is the document written back out and compared with what you pasted in.
Markdown to HTML Converter - Danfio
https://danfio.com/tools/markdown-to-html/ - printed from this page
The HTML for your Markdown
2.1 KB
31 lines of HTML out of 43 lines of Markdown - 4 headings, 3 links and 1 image, with the text surviving a round trip.
Input
195 words 43 lines, 1.4 KB
Output
31 lines 2.1 KB of HTML
Headings
4 the deepest is h4
Links
3 all carried over
Findings
7 nothing to fix
Read back
same words the Markdown, read by this page
Round trip
19 lines written back and compared
The HTML, ready to copy
<h1 id="markdown-to-html-and-back">Markdown to HTML, and back</h1>
<p>Markdown is a small language, and this page is honest about which part of it it speaks. The text you type is converted in the tab you typed it in - <strong>nothing</strong> is uploaded - and the same function produced the HTML below.</p>
<h2 id="what-this-page-does">What this page does</h2>
<ul>
<li>Reads a pipe table with alignment, and a task list</li>
<li><input type="checkbox" checked disabled> Converts fenced code, with the language after the fence</li>
<li><input type="checkbox" disabled> Implements footnotes, which it does not</li>
</ul>
<table>
<thead>
<tr><th style="text-align: left">Setting</th><th style="text-align: right">Default</th><th style="text-align: center">What it changes</th></tr>
</thead>
<tbody>
<tr><td style="text-align: left">tables</td><td style="text-align: right">on</td><td style="text-align: center">GFM only</td></tr>
<tr><td style="text-align: left">line breaks</td><td style="text-align: right">off</td><td style="text-align: center"></td></tr>
</tbody>
</table>
<h4 id="a-sub-subsection-which-skips-a-level">A sub-subsection, which skips a level</h4>
<blockquote>
<p>A quotation, with <strong>emphasis</strong> inside it, and a second paragraph that shows how a quote is
written back out.</p>
<p>Like that.</p>
</blockquote>
<pre><code class="language-js">const heading = document.querySelector('h1');
heading.textContent = 'Markdown';</code></pre>
<pre><code>A fence with no language, which no highlighter can color.</code></pre>
<hr>
<h2 id="setext-headings-work-as-well">Setext headings work as well</h2>
<p>A footnote marker[^1], a phrase someone wanted ==highlighted==, and an ordinary link: <a href="https://example.com/reset">reset your password</a>.</p>
<p>Raw HTML is escaped by default, so <span class="badge">Beta</span> reads as the characters it is.</p>
<p>The guide is <a href="https://example.com/guide" title="The guide">over here</a>, the bare address <a href="https://example.com/bare">https://example.com/bare</a> is recognized, and an image with no alt text looks like this: <img src="/images/diagram.png" alt=""></p>
The first download below is this text byte for byte. Copy it into a file to open it, or straight into a page that takes HTML.
The outline (4 headings)
Level
Heading
Line
h1
Markdown to HTML, and back
1
h2
What this page does
5
h4
A sub-subsection, which skips a level
16
h2
Setext headings work as well
34
A level only means "one deeper than the last", which is why a jump is worth seeing: it reads as a missing section rather than as a smaller font.
The deepest heading here is h4, and its longest heading is 37 characters.
The HTML gets an `id` on every heading, made from the heading text, and a second heading with the same text gets `-1` appended - two elements with one id is invalid HTML, and the second link to it would land on the first.
Headings inside a quotation or a list item are part of that item rather than part of this outline: a table of contents that listed a quotation as a section would be wrong about the document.
The links (3)
Label
Target
Scheme
Line
What happened
reset your password
https://example.com/reset
https
37
kept
over here
https://example.com/guide
https
41
kept, from a definition
https://example.com/bare
https://example.com/bare
https
41
kept
Nothing in this document used a scheme that can run code, so the refusal switch had nothing to do. A scheme of `relative` means the address has none at all - `/about`, `page.html`, `#section` - which is how most links on a page are written. `data:` is refused wherever a link can be clicked, and allowed on an image only as `data:image/...`: an image source is not a navigation target, and a whole HTML document where a picture is expected is how a page ends up running somebody else’s script.
A link written as a reference definition is marked as one: the definition line never becomes content, and it can be pointed at from anywhere in the document.
The images (1)
Alt text
Source
Line
What happened
(none)
/images/diagram.png
41
kept
An image with no alt text renders as `alt=""`, which reads as nothing at all to a screen reader - and to the search engine that indexes the images on a page. An image addressed over `http://` is blocked as mixed content when the page itself is served over `https://`, so it will not appear at all.
This page does not fetch anything: an image is a URL in the text, and nothing here reads the picture it points at.
Code, tables and task lists
Kind
Where
What it is
Size
Code
line 23
js
2 lines
Code
line 28
no language
1 line
Table
line 11
left right center
3 columns, 2 rows
Task list
—
—
1 done, 1 open
A fenced block with no language gets a bare `<pre><code>` and no `class`, which is what a syntax highlighter reads to color it - so a fence with nothing after it is a code block nobody can color. A pipe table has to keep one shape, so a row with a different number of cells is padded or cut to fit and the audit says so: that is where content quietly disappears. A task list item becomes a disabled checkbox in the HTML, which is what GFM produces - and it can be read back as a task, because that checkbox is the one case where HTML says "this was a task".
A table of contents, a heading and a paragraph are not listed here: the outline above already covers the headings, and the paragraphs are what is in the output box.
What the conversion noticed (7 findings)
Area
Line
Level
What it says
Table
14
worth a look
This row has 2 cells and the header row has 3. A pipe table has to keep to one shape, so the row is padded or cut to fit - which is where a cell quietly disappears.
Structure
16
worth a look
Heading levels jump: the heading above this one is h2 and this one is h4. A level only means "one deeper than the last", so the gap is a missing section - to a screen reader, to a table of contents and to a search engine.
Code
28
for information
This code block has nothing after its fence, so the HTML is a bare `<pre><code>` with no `class`. A language there is what a syntax highlighter reads.
Syntax
37
worth a look
`[^1]` is footnote syntax in several Markdown flavors and static-site generators. Nothing here implements footnotes, so the marker is printed as the text it is rather than quietly becoming a note nobody can read.
Syntax
37
worth a look
`==highlighted==` is the highlight marker some flavors use. It is in neither GFM nor CommonMark, so it is printed as text rather than turned into a `<mark>`.
Raw HTML
39
worth a look
The inline HTML `<span class="badge">` on this line was escaped rather than handed to the browser. `<b>` is how a pasted document usually turns up, and passing it through is how a page ends up rendering markup nobody read.
Image
41
worth a look
An image on this line has no alt text. It renders as `<img src="…" alt="">`, which reads as nothing at all to a screen reader.
The columns are the finding's own words: this table is generated from the same sentences the report and the CSV carry, so the page, the report and the download cannot disagree about what was noticed. Every finding is printed here, and the line numbers are the lines of the box above. A round-trip finding is about this page rather than about your document: it means the Markdown this page wrote was read back with different words, which would be a bug here.
The syntax this engine does not implement is reported as the text it will be, rather than being silently printed as if it meant something.
Your Markdown, against the Markdown this page would write back
--- the first text
+++ the second text
@@ -11,7 +11,7 @@
| Setting | Default | What it changes |
| :--- | ---: | :---: |
| tables | on | GFM only |
-| line breaks | off |
+| line breaks | off | |
#### A sub-subsection, which skips a level
@@ -31,13 +31,10 @@
---
-Setext headings work as well
+## Setext headings work as well
-----------------------------
+
-
+A footnote marker\[^1\], a phrase someone wanted ==highlighted==, and an ordinary link: [reset your password](https://example.com/reset).
-A footnote marker[^1], a phrase someone wanted ==highlighted==, and an ordinary link: [reset your password](https://example.com/reset).
+
-
+Raw HTML is escaped by default, so \<span class="badge">Beta\</span> reads as the characters it is.
-Raw HTML is escaped by default, so <span class="badge">Beta</span> reads as the characters it is.
+
-
+The guide is [over here](https://example.com/guide "The guide"), the bare address [https://example.com/bare](https://example.com/bare) is recognized, and an image with no alt text looks like this: 
-The guide is [over here][the-guide], the bare address <https://example.com/bare> is recognized, and an image with no alt text looks like this: 
-
-[the-guide]: https://example.com/guide "The guide"
11 lines of the original are gone and 8 are new. A round trip through another language is not the identity, and this is where the difference is: re-spelled emphasis, a list written tight or loose, a table padded to keep its shape. What must not change is the words, and the read-back check above is what tests that.
The rules in force
Decision
What it does
Direction
Markdown into HTML
Dialect
GFM: pipe tables, task lists, strikethrough and bare links are all read and written
Raw HTML
escaped into text, because a pasted document is untrusted input
Unsafe schemes
`javascript:`, `vbscript:`, `data:` and `file:` are refused where a link can be clicked, with the line printed
added to every heading, made from its text, with `-1` on a repeat
A single newline
stays a newline in the HTML source, which a browser draws as a space
Output
the fragment only, ready to paste inside an existing page
Table alignment
written as `style="text-align: …"`, which is what the living standard asks for, rather than the deprecated `align` attribute
Indented code
four spaces does not start a code block here, which is a deviation from CommonMark: use a fence
List continuation
a continuation line has to be indented to the item’s text, which is the other deviation: no lazy continuation
Not implemented
footnotes, definition lists, math, `==highlight==`, alert blockquotes, containers, attribute blocks and emoji shortcodes are recognized and reported as text rather than converted
Two of these are deviations from CommonMark - indented code and lazy continuation - and they are printed rather than hidden, along with the syntax the engine does not implement at all. The dialect, the raw-HTML setting and the scheme setting are the three the page argues about in its explanation below; the rest are implementation choices with one sensible answer each.
A converter that lists its own decisions is a converter you can predict, which matters more here than speed: the HTML ends up on a page that other people read.
The syntax this engine implements
Headings: `#` to `######`, and the underlined `===` / `---` form
Paragraphs separated by a blank line, with hard breaks from two trailing spaces or a trailing backslash
Blocks: `>` quotes, `-` and `1.` lists (nested, tight or loose, with `start`), `---` rules, fenced code in backticks or tildes
GFM only: pipe tables with alignment, task list items, `~~strikethrough~~`, links written bare in the text
What the numbers do not say
The engine implements a named subset rather than a specification, and the rules table below prints it - including the two places it deviates from CommonMark: four spaces does not start a code block, and a list continuation line has to be indented.
The read-back check is about this page rather than about your document: the Markdown it wrote was read by its own parser and the words were compared. Structure may be re-spelled on the way; a changed word would be a bug here, and the finding says where.
Nothing going this way is dropped, because Markdown is the smaller language: everything it can say has somewhere to go in HTML. Coming back, some elements have no Markdown equivalent, and the table of what could not be kept names them.
Raw HTML is escaped by default, and that is a decision rather than a limitation: a document pasted into a converter is untrusted input, and handing its markup straight to the browser is how a converter becomes the last step of an injection.
The answer is the source, not a preview. This page prints the HTML it produced instead of putting it into itself, because a viewer that draws somebody else’s markup is exactly what the escaping above exists to avoid. Paste the result into a file to see it drawn.
Converted in this tab by the same function that produced the HTML already in the page you loaded, so nothing was sent anywhere - which matters here more than on most pages, because the document people paste into a converter is often somebody else’s page or a draft nobody has published yet.
It is not a CommonMark implementation and never claims to be. It speaks a named subset, prints it below, and names the two places where it deliberately deviates. Syntax it recognizes but does not implement - a footnote marker, `$math$`, `==highlight==`, a GitHub alert - is *reported* as the text it will become rather than quietly printed as if it meant something, which is the difference between a converter you can trust and one that publishes `[^1]` in the middle of a post.
The answer is the source, not a preview. This page prints the HTML it produced instead of putting it into itself, because a viewer that draws somebody else’s markup is exactly what the escaping exists to avoid. Paste the result into a file to see it drawn - it opens as it is if you chose a whole document.
About this markdown to html converter
Had you pasted a document into one converter and a page into another, you would have two mental models and one source of truth. This page does both directions in one place: Markdown to HTML and HTML back to Markdown, with the outline, every link and its scheme, whatever could not be carried, and the round trip printed beside the answer.
Nothing is uploaded, because there is no endpoint behind the page that could accept a draft: both conversions are functions of the text and run in the tab you are reading. That matters most for the round trip, which rewrites your own document and compares it with the original - a private draft is never the price of seeing what a converter changed.
It is not a CommonMark implementation and never pretends to be: it speaks a named subset, prints it below the box, and names the two places it deliberately deviates. Syntax it recognizes but does not implement is reported as the text it would become rather than quietly printed, so a footnote marker or a math span never slips into a post looking like something it is not.
How this markdown to html converter works
How a document is carried between the two formats
Both directions read the same structure - headings, paragraphs, quotes, lists, code and tables - and write it out in the other language. That is why a document can go from Markdown to HTML and back without losing its words: the second conversion starts from what the first one understood, rather than from a second guess at the text.
The round trip on this page is the document written back and compared with what you pasted. Every difference it reports is a difference between the two languages - an emphasis mark re-spelled, a list that changed shape - rather than a slip in the conversion.
What is filtered, and why
Markdown from somebody else is untrusted input, and a converter is the place where untrusted input becomes markup. So every character of text is escaped - `<`, `>`, `&` and `"` become entities, and the only ampersands left alone are the ones that were already entity references. A raw HTML block is escaped by default too: `<div class="note">` becomes `<div class="note">` and reads as the characters it is. There is a switch for passing it through, because CommonMark says to pass it through, and because your own markup is not somebody else’s.
Links get their own rule, and it is the one that matters most in practice. A `javascript:` address in a link is how a page ends up running code that arrived inside a document, and `data:text/html,...` is a whole document where a link was expected. Both are refused by default wherever a link can be clicked, and every refusal is printed with the line it happened on. What is *not* refused is `data:image/...` in an image: an image source is not a navigation target, so carrying pixels inline is an ordinary thing to do, and only the scheme tells the two apart. The check reads the address the way a browser does - after decoding, with whitespace removed - so `javascript:` and `java	script:` are caught as well.
The read-back check: what the round trip tells you
The Markdown this page writes is read back and compared with the text of the two documents. If a word changed, the report says so and shows where. Structure is allowed to change on the way - `_emphasis_` is written back as `*emphasis*`, a list may come back with its blank lines arranged differently - because those are the same document in another spelling, and the report says which of the two it found.
Runs of whitespace are collapsed before the comparison, so re-flowing a paragraph is not a difference. A changed word is. That is a narrow promise, it is stated on the page, and the round trip beside every answer is the evidence for it.
What Markdown cannot carry, and what this page will not do
Markdown is the smaller language, so the direction that goes into it loses things: a `<div>` has no equivalent and is unwrapped, a `<span>` disappears while its words stay, `<sup>` becomes ordinary text because there is no superscript syntax, and a `<script>` is dropped rather than converted. None of that is left for the visitor to discover afterwards - the table of what could not be kept names the element, how often it appeared and what happened to it.
In the other direction nothing is dropped, because everything Markdown can say has somewhere to go in HTML. What that direction has instead is a list of syntax it declines to interpret: footnotes, definition lists, display and inline math, `==highlight==`, alert blockquotes, containers, attribute blocks and emoji shortcodes are all recognized and reported as the text they will be. Two deviations from CommonMark are printed as well: four spaces does not start a code block here (use a fence), and a list continuation line has to be indented to the item’s text, so there is no lazy continuation.
Worked examples
Each example below was run through the calculator on this page when the site was built, so the numbers match what you see when you enter the same inputs.
A short README, with a list and a table
Which way: Markdown into HTML · The Markdown: # Widget
- Built with **care**
- [x] Tested
| Flag | Default |
| --- | ---: |
| `--fast` | off | · Which Markdown: GFM: tables, tasks, strikethrough, bare links
The HTML for your Markdown
349 B
13 lines of HTML out of 8 lines of Markdown - 1 heading, 0 links and 0 images, with the text surviving a round trip.
The hero above is the size of the HTML that came out; the statistics are the page’s own counts, and the outline, the links and the audit are printed beside the answer when the page is being used.
A page from a CMS, turned back into Markdown
Which way: HTML into Markdown · The HTML: <h2>Notes</h2>
<p>A <strong>paragraph</strong> with a <a href="/guide">link</a> and a <sup>marker</sup>.</p>
<div><p>In a div, which Markdown has no container for.</p></div>
The Markdown for your HTML
110 B
5 lines of Markdown out of 3 lines of HTML - 1 heading, 1 link and 0 images, with the text surviving a round trip.
Going this way Markdown is the smaller language, so the table of what could not be kept names the `<sup>` and the `<div>` - and the words inside them survive all the same.
A link that can run code, refused and reported
Which way: Markdown into HTML · The Markdown: Reset your password [here](javascript:alert(1)) and keep the . · A link that can run code: Refuse it, keep the words
The HTML for your Markdown
97 B
1 line of HTML out of 1 line of Markdown - 0 headings, 1 link and 1 image, with the text surviving a round trip.
The words of the link stay and its destination does not: the switch above is what decides that, and the audit prints the line it happened on. The image is a different case, and is allowed to carry its pixels inline.
Frequently asked questions
Is this a CommonMark implementation?+
No, and the page says which subset it does implement rather than implying the rest. Both directions follow the CommonMark rules where they overlap - the flanking rule that decides what `snake_case` and `2*3*4` mean, the order in which a fence beats a heading, an underlined heading beating a thematic break - and there are two places where the behavior deliberately differs. Four spaces does not start a code block, and a list continuation line has to be indented to the item’s text. Both are printed in the rules table, so nothing about the output is a surprise.
Why is there no rendered preview?+
Because a preview means drawing somebody else’s markup inside this page, and that is exactly the risk the escaping exists to remove. The answer this page gives is the source: the HTML it produced, ready to copy or download. Paste it into a file - or choose a whole document - and a browser draws it there, in its own tab, where a mistake is a mistake in your file rather than in this page.
What happens to a link like `javascript:alert(1)`?+
By default it is refused: the words of the link stay and the address is dropped, because deleting the sentence would be a bigger change than the one that was asked for. The refusal is printed in the audit with the line number, and the switch on the form turns the rule off for documents you wrote yourself. The check runs on the decoded, whitespace-stripped address, so `javascript:` is refused as well - a browser reads it as `javascript:`, so this page has to.
Why is raw HTML escaped rather than passed through?+
Because a document pasted into a converter is usually somebody else’s, and passing its markup through is how a converter becomes the last step of an injection. Escaped, `<div onclick="...">` becomes visible text that a reader can see and a browser cannot act on. CommonMark says a renderer should pass raw HTML through, and the switch does exactly that for the case CommonMark has in mind: your own markup, in your own document.
Is my document uploaded anywhere?+
No. The conversion follows a fixed rule applied to the text, so it runs in the tab you typed it in, and there is no endpoint behind the page that could accept a document even if something tried to send one. That matters here more than on most pages: the thing people paste into a converter is often a draft nobody has published, or a competitor’s page.
What is the round trip telling me?+
It is the document written back out in the form it came from and diffed against what you pasted. A round trip through another language is not the identity, so the interesting part is *where* it differs: emphasis re-spelled from `_x_` to `*x*`, a list re-arranged from tight to loose, a table padded to keep its shape. What may not change is the words, and the read-back check beside it is what tests that - if a word changed, the page says so and shows where.
Why does `_emphasis_` come back as `*emphasis*`?+
Because they are the same document in two spellings, and the page writes each thing one way. The alternative - remembering which spelling the visitor used - would mean carrying the original text along, and then the round trip would be testing itself rather than testing the two languages.
What happens to syntax the page does not implement?+
It is recognized and reported. A footnote marker, `$math$`, `==highlight==`, a GitHub alert, a definition list, a container directive, an attribute block and an emoji shortcode all appear in the audit as the text they will become, with the line they are on. That is the whole difference between a converter you can trust and one that publishes `[^1]` in the middle of a post without telling you.
Assumptions and sources
Conversions follow GitHub Flavored Markdown (GFM) and CommonMark. The dialect switch turns pipe tables, task lists, strikethrough and bare links on or off.
All links and raw HTML are filtered: `javascript:`, `vbscript:` and `data:text/html` addresses are refused, and `data:image/...` is allowed on images only.
Safety and privacy: the conversion runs in your browser, nothing is uploaded, and every change is shown beside the answer.
Last reviewed 2026-09-18. Runs locally on your device; keep backups; no financial advice applies. Read the full disclaimer.
Where a figure on this page comes from an official agency — HUD, IRS, FICO or a state body — the site keeps a dated snapshot of the source page in its sources library, and a scheduled job re-checks that snapshot, so the number can be traced back to the document it came from.