HTML to Markdown

Convert HTML back into Markdown, keeping the common block and inline elements.

Convert HTML to Markdown

Blocks: — · Status: —
Conversion runs locally in your browser. Paragraphs, headings, lists, links, images and code blocks are rebuilt as Markdown.

How to use the HTML to Markdown

  1. Paste your HTML into the input box.
  2. Press Convert to Markdown to rebuild the text.
  3. Copy the Markdown output with the Copy Markdown button.

Features

Advertisement

Frequently Asked Questions

Common questions about the free online html to markdown.

Paste your HTML into the input box and press Convert to Markdown. The Markdown source appears instantly in the output box.
Headings, paragraphs, strong and em, links, images, unordered and ordered lists, blockquotes, code, pre and horizontal rules.
Tags outside the supported set are dropped while their text content is kept, so nothing readable is lost from the page.
Yes. Script and style elements are skipped completely, so no JavaScript or CSS text ends up inside the Markdown output.
Named and numeric character references are decoded, so escaped ampersands and angle brackets turn back into normal characters.
A list inside a list item is indented by two spaces under its parent, keeping the Markdown list structure valid.
Tables are flattened to plain text lines, because the supported Markdown subset has no table syntax.
Only the address of links, the source and alt text of images and the language class of code blocks are carried over.
No. The conversion runs entirely in your browser and your markup never leaves your device.
Yes. It is completely free, unlimited and works in any modern browser without an account.

Last updated: October 10, 2026

' ].join('\n'); var VOID = { br: 1, hr: 1, img: 1, input: 1, meta: 1, link: 1, area: 1, base: 1, col: 1, embed: 1, source: 1, track: 1, wbr: 1 }; function decode(s) { return String(s) .replace(/</g, '<') .replace(/>/g, '>' ) .replace(/"/g, '"' ) .replace(/'/g, "'" ) .replace(/&#(\d+);/g, function (m, d) { return String.fromCharCode(parseInt(d, 10)); }) .replace(/&#x([0-9A-Fa-f]+);/g, function (m, h) { return String.fromCharCode(parseInt(h, 16)); }) .replace(/&/g, '&' ); } function tagEnd(s, from) { var quote='' ; for (var i=from; i < s.length; i++) { var c=s.charAt(i); if (quote) { if (c===quote) quote='' ; continue; } if (c==='"' || c==="'" ) { quote=c; continue; } if (c==='>' ) return i; } return -1; } function parseAttrs(str) { var attrs={}; var re=/([A-Za-z_:][-A-Za-z0-9_:.]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g; var m; while ((m = re.exec(str))) { var v = m[2] || ''; if (v.length > 1 && (v.charAt(0) === '"' || v.charAt(0) === "'")) v = v.slice(1, -1); attrs[m[1].toLowerCase()] = decode(v); } return attrs; } function parseHtml(src) { var s = String(src); var pos = 0; var n = s.length; var root = { tag: '#root', attrs: {}, kids: [] }; var stack = [root]; function top() { return stack[stack.length - 1]; } while (pos < n) { var lt=s.indexOf('<', pos); if (lt < 0) { top().kids.push({ tag: '#text' , text: s.slice(pos) }); break; } if (lt> pos) top().kids.push({ tag: '#text', text: s.slice(pos, lt) }); if (s.substr(lt, 4) === '', lt); pos = c1 < 0 ? n : c1 + 3; continue; } if (s.substr(lt, 9)==='', lt); top().kids.push({ tag: '#text', text: s.slice(lt + 9, c2 < 0 ? n : c2) }); pos=c2 < 0 ? n : c2 + 3; continue; } var nxt=s.charAt(lt + 1); if (nxt==='!' || nxt==='?' ) { var c3=s.indexOf('>', lt); pos = c3 < 0 ? n : c3 + 1; continue; } var gt=tagEnd(s, lt + 1); if (gt < 0) { top().kids.push({ tag: '#text' , text: s.slice(lt) }); break; } var raw=s.slice(lt + 1, gt); pos=gt + 1; if (raw.charAt(0)==='/' ) { var closing=raw.slice(1).replace(/\s+$/, '' ).toLowerCase(); for (var k=stack.length - 1; k> 0; k--) { if (stack[k].tag === closing) { stack.length = k; break; } } continue; } var selfClose = /\/\s*$/.test(raw); var body = selfClose ? raw.replace(/\/\s*$/, '') : raw; var sp = body.search(/\s/); var tag = (sp < 0 ? body : body.slice(0, sp)).toLowerCase(); if (tag==='script' || tag==='style' ) { var closeAt=s.toLowerCase().indexOf('', closeAt); pos = endAt < 0 ? n : endAt + 1; continue; } var node={ tag: tag, attrs: parseAttrs(sp < 0 ? '' : body.slice(sp)), kids: [] }; top().kids.push(node); if (!selfClose && !VOID[tag]) stack.push(node); } return root; } function textOf(node) { var s='' ; for (var i=0; i < node.kids.length; i++) { var k=node.kids[i]; if (k.tag==='#text' ) s +=decode(k.text); else s +=textOf(k); } return s; } function renderInline(node) { if (node.tag==='#text' ) return decode(node.text).replace(/\s+/g, ' ' ); var inner='' ; for (var i=0; i < node.kids.length; i++) inner +=renderInline(node.kids[i]); if (node.tag==='strong' || node.tag==='b' ) return '**' + inner.replace(/^\s+|\s+$/g, '' ) + '**' ; if (node.tag==='em' || node.tag==='i' ) return '*' + inner.replace(/^\s+|\s+$/g, '' ) + '*' ; if (node.tag==='del' || node.tag==='s' || node.tag==='strike' ) { return '~~' + inner.replace(/^\s+|\s+$/g, '' ) + '~~' ; } if (node.tag==='code' ) return '`' + inner.replace(/`/g, '' ) + '`' ; if (node.tag==='a' ) { var href=node.attrs.href || '' ; return href ? '[' + inner + '](' + href + ')' : inner; } if (node.tag==='img' ) { return '![' + (node.attrs.alt || '' ) + '](' + (node.attrs.src || '' ) + ')' ; } if (node.tag==='br' ) return '\u0001' ; return inner; } function restore(s) { return s.replace(/\u0001/g, '\n' ); } function repeat(ch, n) { var s='' ; for (var i=0; i < n; i++) s +=ch; return s; } function renderList(node) { var ordered=node.tag==='ol' ; var lines=[]; var index=1; for (var i=0; i < node.kids.length; i++) { var li=node.kids[i]; if (li.tag !=='li' ) continue; var inline='' ; var nested='' ; for (var j=0; j < li.kids.length; j++) { var c=li.kids[j]; if (c.tag==='ul' || c.tag==='ol' ) nested +=renderList(c); else if (c.tag==='p' ) inline +=renderInline(c); else inline +=renderInline(c); } inline=restore(inline.replace(/\s+/g, ' ' )).replace(/^\s+|\s+$/g, '' ); lines.push((ordered ? (index++) + '.' : '-' ) + ' ' + inline); if (nested) { var parts=nested.replace(/\n+$/, '' ).split('\n'); for (var q=0; q < parts.length; q++) lines.push(' ' + parts[q]); } } return lines.join(' \n') + '\n' ; } function renderBlocks(kids) { var parts=[]; var buf='' ; function flush() { var t=restore(buf.replace(/\s+/g, ' ' )).replace(/^\s+|\s+$/g, '' ); if (t) parts.push(t); buf='' ; } for (var i=0; i < kids.length; i++) { var k=kids[i]; if (k.tag==='#text' ) { buf +=decode(k.text); continue; } if (k.tag==='p' ) { flush(); var ptext=restore(renderInline(k).replace(/\s+/g, ' ' )).replace(/^\s+|\s+$/g, '' ); if (ptext) parts.push(ptext); continue; } if (/^h[1-6]$/.test(k.tag)) { flush(); var level=parseInt(k.tag.charAt(1), 10); var heading=restore(renderInline(k).replace(/\s+/g, ' ' )).replace(/^\s+|\s+$/g, '' ); if (heading) parts.push(repeat('#', level) + ' ' + heading); continue; } if (k.tag==='pre' ) { flush(); var code=textOf(k).replace(/^\n+|\n+$/g, '' ); var lang='' ; if (k.kids.length===1 && k.kids[0].tag==='code' ) { var m=/language-([A-Za-z0-9+#._-]+)/.exec(k.kids[0].attrs['class'] || '' ); if (m) lang=m[1]; } parts.push('```' + lang + '\n' + code + '\n```' ); continue; } if (k.tag==='blockquote' ) { flush(); var inner=renderBlocks(k.kids); if (inner) { var qlines=inner.split('\n'); var quoted=[]; for (var q=0; q < qlines.length; q++) { quoted.push(qlines[q] ? '> ' + qlines[q] : '>' ); } parts.push(quoted.join('\n')); } continue; } if (k.tag==='ul' || k.tag==='ol' ) { flush(); var list=renderList(k).replace(/\n+$/, '' ); if (list) parts.push(list); continue; } if (k.tag==='hr' ) { flush(); parts.push('---'); continue; } if (k.tag==='br' ) { buf +='\u0001' ; continue; } buf +=renderInline(k); } flush(); return parts.join('\n\n'); } function reset(msg) { out.value='' ; count.textContent='—' ; status.textContent='—' ; if (msg) window.ffeeToast(msg); } function convert(report) { var text=input.value; if (!text.replace(/\s+/g, '' )) { if (report) reset('Paste some HTML first.'); else reset(''); return; } var doc=parseHtml(text); var md=renderBlocks(doc.kids); out.value=md ? md + '\n' : '' ; count.textContent=String(md ? md.split('\n\n').length : 0); status.textContent=md ? 'Converted' : 'Nothing to convert' ; } document.getElementById('hmRun').addEventListener('click', function () { convert(true); }); document.getElementById('hmSample').addEventListener('click', function () { input.value=SAMPLE; convert(true); }); document.getElementById('hmCopy').addEventListener('click', function () { if (out.value) window.ffeeCopy(out.value, 'Markdown' ); }); document.getElementById('hmClear').addEventListener('click', function () { input.value='' ; reset(''); }); input.addEventListener('input', function () { convert(false); }); convert(false); })();