gizmobench

HTML to Markdown

Paste HTML in one pane and read GitHub Flavored Markdown in the other: headings, paragraphs, emphasis, links, images, inline code, fenced code blocks, blockquotes, nested ordered and unordered lists, task items and pipe tables with their column alignment. What this page does that the others on this search do not is tell you what it could not carry across. Every script, style, iframe, form control, comment, spanning table cell and flattened cell is counted into a notes panel under the output, so a colspan that a pipe table cannot hold is something you are told about instead of something you find later. The markup is never handed to a browser parser and never rendered: it is read as characters, which is why nothing in it, no image, stylesheet, font or link, is ever fetched, and why a script is dropped without being run.

markdownGFM
## Setup - Install 1. npm i ``` npm run dev ```

notes: 1 script element dropped

Flavour
Nested lists
2 levels, indented
Scripts
1 dropped
Requests made
0

8 lines of GFM Markdown, 1 note.

1 thing here that Markdown could not carry across as it stands. Each one is listed rather than left for you to find missing later.

  • 11 script element removed. The code inside was skipped as characters, never run, and none of it is in the Markdown.
  • Ordered list inside a bullettwo levels
    - Install 1. npm i 2. npm run build
  • A script element in the sourceany contents
    Pricesnotes: 1 script element dropped
  • Table with a right-aligned column3 columns
    | Item | Qty | Price | | --- | :---: | ---: | | Bolt | 4 | 1.20 |
Accuracy. Conversion runs over an inert parse of the HTML you paste: scripts and styles are removed without running, and no image, stylesheet, font or link in the markup is ever fetched. Tables keep their alignment. Anything Markdown cannot express is listed in a notes panel rather than silently dropped, and nothing leaves your browser.

Up to 2,000,000 characters in one pass, read here in your browser with nothing uploaded and no account. GFM writes pipe tables, task items and strikethrough; CommonMark has none of those, so a table is kept as plain HTML and the other two are reported. The flavour and the draft are kept in this browser alone, drafts up to 200,000 characters, and the Start over button above the tool forgets both.

Common questions

Does this page run the HTML I paste, or fetch anything in it?
Neither, and neither can happen by accident. The converter never hands your markup to a browser parser, because a parsed node is one attribute away from requesting an image, a font or a stylesheet from a host that then knows your paste exists. It reads the markup as characters instead, so an image source, a stylesheet link, a font or a link target is copied into the Markdown without ever being resolved. That is why the readout cell marked Requests made is a constant rather than a counter: there is no code path on this page that could raise it above zero. Script and style contents are skipped as characters too, so nothing in them is ever evaluated.
What happens to a script or a style tag?
It is dropped, and it is counted. Script, style, textarea and title hold content that is not markup, so the reader skips over them and none of what is inside reaches the output. What you get instead is a line under the Markdown: for the sample this page opens with, it reads notes: 1 script element dropped. The same goes for an iframe, a video, a form control, an HTML comment and the head elements, title, meta and base. Every drop is a line in the notes panel, because a converter that quietly loses an iframe is worse than one that says so.
Do tables keep their alignment?
Yes, on the GFM setting. A column aligned right in the HTML, whether by an align attribute on the cell or by a text-align rule in its style attribute, comes back as three hyphens and a colon in the separator row; a centred column gets a colon at both ends and a left column gets one at the start. When the header cell says nothing about alignment, the first body row decides the column, which is how most real tables carry it. A table that arrives with no header row gets an empty one, because a pipe table must have a header, and the notes say that happened. A cell with a colspan or a rowspan keeps its text and loses the span, and a cell holding two paragraphs or a line break is joined into one line, because a pipe table row is one line. Both are notes as well.
How are nested lists and code blocks handled?
A list inside a list is indented by the width of the marker holding it, which is what GitHub and every CommonMark renderer read back as nesting. The sample this page opens with, an ordered list inside a bullet, comes out as a hyphen and Install, with 1. npm i indented two spaces under it. An ordered list that starts at nine keeps counting from nine, and its children indent three spaces, because that marker is three characters wide. A pre block comes back fenced with backticks, with the language after the opening fence when a class such as language-js names one, and a block that already contains a fence of its own gets a longer one so nothing closes early. Entities inside the code are decoded and nothing in it is escaped.
What do the GFM and CommonMark buttons change?
Three things, and each one is a GFM extension that CommonMark does not have: pipe tables, strikethrough and task list items. GFM writes all three. On CommonMark a table is written as plain HTML instead, which CommonMark allows, with its cell text and its column alignment kept and every other attribute dropped; a struck-through run is written without its marks; and a checkbox becomes an ordinary list item. None of the three is silent: each one is a line in the notes panel that names the setting to switch back to.
Why does the output have backslashes in it?
Because the text you pasted is text, and it has to read back as text. An asterisk, an underscore, a square bracket, a backtick, or a line that opens with a hash or a hyphen, would otherwise become formatting that was never in your document, so each one is escaped. The opening angle bracket is escaped for a stronger reason: markup that arrived as text, a tag quoted as an example on a documentation page for instance, would otherwise reach the next Markdown renderer as live HTML, and most Markdown renderers pass raw HTML straight through. A backslash in front of it means the next renderer prints it instead.
How much HTML can I convert at once, and is any of it kept?
Up to 2,000,000 characters in one pass, which is a large page several times over. Past that the page says how large your paste is and how large it may be, and converts nothing until you split it up: it never truncates, because a converter that silently dropped the end of your document would be worse than one that refused it. Markup nested more than 400 elements deep is refused the same way, with the depth named. Your draft is kept on this device alone, up to 200,000 characters of it, along with the flavour you chose; a longer paste still converts in full and is simply not stored, and the Start over button above the tool forgets both.
Can I paste a whole page I copied from the browser?
Yes. Paste the page source and the head goes: title, meta and base are counted in the notes and dropped, because they describe the page rather than its content. A wrapper with no meaning of its own, a div, a section, an article, a header or a footer, is unwrapped and its text kept, so what you are left with is the reading matter. A link whose target is a javascript, data or file URL keeps its words and loses its target, and that is a note too: a Markdown link that runs code is not something this page will write for you.

Conversion runs over an inert parse of the HTML you paste: scripts and styles are removed without running, and no image, stylesheet, font or link in the markup is ever fetched. Tables keep their alignment. Anything Markdown cannot express is listed in a notes panel rather than silently dropped, and nothing leaves your browser.