webdevpuneet.com

Turndown HTML to Markdown Converter — Free Paste-to-Markdown Snippet

Turndown HTML to Markdown Converter (Paste Rich Text, Get Markdown) · Tools · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="td">
  <header class="td-head">
    <div>
      <h2>Rich text → Markdown</h2>
      <p>Paste from Google Docs, a web page or an email into the left pane — or edit the sample. Markdown updates as you type.</p>
    </div>
    <div class="td-opts">
      <label>Headings <select id="tdHeading"><option value="atx"># ATX</option><option value="setext">Setext ===</option></select></label>
      <label>Bullets <select id="tdBullet"><option>-</option><option>*</option><option>+</option></select></label>
      <label>Code <select id="tdCode"><option value="fenced">&#96;&#96;&#96; fenced</option><option value="indented">indented</option></select></label>
      <label class="td-check"><input type="checkbox" id="tdGfm" checked> GFM tables &amp; ~~strike~~</label>
    </div>
  </header>
  <div class="td-grid">
    <section class="td-pane">
      <div class="td-label">HTML input <button type="button" id="tdClear" class="td-mini">Clear</button></div>
      <div class="td-edit" id="tdEdit" contenteditable="true" aria-label="Rich text input" spellcheck="false"></div>
    </section>
    <section class="td-pane">
      <div class="td-label">Markdown output <span id="tdStats"></span> <button type="button" id="tdCopy" class="td-mini">Copy</button></div>
      <textarea id="tdOut" readonly aria-label="Markdown output" spellcheck="false"></textarea>
    </section>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Live conversion
Markdown updates as you edit.
Style options
ATX/setext, bullet marker, fenced/indented code.
GFM plugin
Tables, strikethrough and task lists.
Custom highlight rule
mark becomes ==text==.
Element removal
Scripts and styles never leak into output.
Clean paste
Inline styles and classes stripped from pasted HTML.
Clipboard fallback
Select-to-copy when the API is unavailable.
Line and word count
Quick size check of the result.

About this UI Snippet

Turndown — Turning Pasted Rich Text Into Clean Markdown

Screenshot of the Turndown HTML to Markdown Converter (Paste Rich Text, Get Markdown) snippet rendered live

Markdown is easy to write but tedious to convert into: copying formatted text from a document or web page into a Markdown field loses links, lists and headings. Turndown does the reverse of a Markdown renderer — it walks an HTML tree and emits Markdown. This snippet wires it to a rich-text pane so pasting formatted content produces Markdown immediately.

Options map to style guides

Turndown's options decide the flavour of the output: headingStyle chooses # Heading (ATX) or underlined (setext) headings, bulletListMarker picks -, * or +, and codeBlockStyle chooses fenced blocks or four-space indentation. Changing a dropdown re-creates the service and converts again, so you can match whatever your project's linter expects.

GitHub Flavored Markdown via a plugin

Core Markdown has no tables or strikethrough, so core Turndown drops them. The turndown-plugin-gfm plugin adds rules for tables (with header rows), strikethrough and task-list checkboxes. Uncheck GFM to see the table collapse into plain text. The plugin writes strikethrough with single tildes, which the GFM spec allows but many other parsers don't, so the snippet adds its own rule for ~~double~~ tildes. Rules added later are checked first, which is how it overrides the plugin.

Custom rules

addRule(name, { filter, replacement }) teaches Turndown about elements it doesn't know. The sample includes <mark>, which standard Markdown can't express; the rule outputs ==text==, the highlight syntax used by many editors. remove() drops scripts and styles entirely instead of leaking their content as text.

Pasting from Google Docs and Word

Pasted HTML arrives covered in inline styles, class names and wrapper spans. The paste handler parses the clipboard's HTML with DOMParser, strips style, class and id attributes and non-content elements, then inserts the cleaned fragment at the cursor. Formatting that carries meaning — headings, bold, links, lists — survives.

Copying the result

The Clipboard API needs a secure context and permission, which sandboxed frames may not have, so the copy button falls back to selecting the Markdown for a manual Ctrl+C.

Step by step

How to Use

  1. 1
    Start from the sampleRelease notes with headings, lists, code, a quote and a table.
  2. 2
    Paste your own contentFrom Google Docs, Word, email or a web page.
  3. 3
    Choose a styleHeading, bullet and code-block options update the output.
  4. 4
    Toggle GFMSee tables and strikethrough appear or disappear.
  5. 5
    Copy the MarkdownUse Copy, or select and Ctrl+C if the clipboard is blocked.

Real-world uses

Common Use Cases

Docs and blog drafting
Move drafts from Google Docs or Word into Markdown by pasting rich text, keeping links, lists and headings that a plain paste would lose.
README writing
Convert formatted notes into GitHub-flavoured Markdown, with a GFM plugin supplying tables, strikethrough and task lists.
CMS and site migrations
Turn exported HTML into Markdown files, choosing ATX or setext headings, a bullet marker and fenced or indented code blocks.
Note-taking apps
Accept rich paste from anywhere and store clean Markdown, with a custom rule turning mark elements into ==text== highlights.
Chat and AI input cleaning
Normalise pasted content before sending it to a model or chat, so formatting survives as readable plain text.
Related: Markdown Live Preview
Related: Rich Text Editor
Produce the HTML in the first place: Quill Rich Text Editor with Custom Toolbar.

Got questions?

Frequently Asked Questions

Create a TurndownService with your preferred options and call service.turndown(htmlStringOrNode). It returns a Markdown string.

Core Markdown has no table syntax, so Turndown ignores table structure by default. Add the turndown-plugin-gfm plugin with service.use(turndownPluginGfm.gfm).

Add a rule: service.addRule('name', { filter: 'tag' or a function, replacement: function (content, node) { return ...; } }). Use service.keep() to keep the raw HTML, or service.remove() to drop it.

Read the clipboard's text/html, parse it with DOMParser, remove style, class and id attributes and non-content elements, then insert the cleaned HTML and convert it.

Turndown only produces text; it doesn't execute scripts. But if you later render the Markdown back to HTML, sanitise that output (for example with DOMPurify), because Markdown can contain raw HTML and links.