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

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.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet into an AI assistant like Claude and ask it how Turndown's rules are matched and why the GFM plugin is needed for tables. Ask it to add rules for figures with captions, callout boxes, or footnotes; to convert images to reference-style links; or to add a side-by-side rendered preview of the Markdown. It can also help tune the paste cleaner for a specific source like Notion.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a live HTML-to-Markdown converter with Turndown and turndown-plugin-gfm (both from a CDN) in plain HTML, CSS and JavaScript.

Requirements:
- A contenteditable rich-text pane preloaded with sample release notes (h1, h2, paragraph with bold, italic and a link, nested list with a highlighted phrase and a strikethrough item, ordered list, fenced bash code block, blockquote, table) and a read-only Markdown output pane.
- Options for heading style (ATX or setext), bullet marker (-, *, +), code block style (fenced or indented) and a GFM toggle; changing any option re-creates the Turndown service and converts again.
- Use the GFM plugin when enabled, add a custom rule converting mark elements to ==text==, and remove script, style and meta elements.
- Convert on input (debounced) and show line and word counts.
- On paste, if the clipboard has HTML, parse it with DOMParser, strip style, class and id attributes and non-content elements, and insert the cleaned HTML at the cursor.
- A copy button using the Clipboard API with a fallback that selects the output text, and a clear button.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

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>

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 blogging
Move drafts from Google Docs into Markdown sites.
README writing
Convert formatted notes into GitHub Markdown.
CMS migrations
Turn exported HTML into Markdown files.
Note-taking apps
Accept rich paste, store Markdown.
Chat and AI tools
Normalise pasted content before sending.
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.