Convert Markdown to HTML and HTML to Markdown
Whether you're building a blog, content management system (CMS) or a documentation site, converting between Markdown and HTML is a common task in modern web development.
In this guide, we'll show you how to easily convert Markdown to HTML and HTML back to Markdown using JavaScript libraries like unified, remark, rehype, and turndown.
Why Convert Between Markdown and HTML?
-
Markdown to HTML: Needed for rendering Markdown content in browsers.
-
HTML to Markdown: Useful when editing previously rendered content or importing HTML from external sources.
Required Libraries
To perform these conversions, we'll use the following packages
Task | Package |
---|---|
Parse Markdown | remark-parse |
Convert Markdown AST → HTML AST | remark-rehype |
Serialize HTML AST → HTML | rehype-stringify |
Convert HTML → Markdown | turndown , turndown-plugin-gfm |
Installation
Install all necessary dependencies using npm or yarn:
npm install unified remark-parse remark-rehype rehype-stringify turndown turndown-plugin-gfm
Or using yarn
yarn add unified remark-parse remark-rehype rehype-stringify turndown turndown-plugin-gfm
Setting Up the Markdown ↔ HTML Utility
Now let’s implement a simple yet powerful utility to convert Markdown to HTML and vice versa.
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import rehypeStringify from "rehype-stringify";
import TurndownService from "turndown";
import { gfm } from "turndown-plugin-gfm";
/**
* Convert Markdown → HTML (synchronous)
*/
const markdownToHtml = (markdown) => {
const file = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.processSync(markdown);
return String(file);
};
/**
* Convert HTML → Markdown
*/
const htmlToMarkdown = (html) => {
const turndown = new TurndownService({
headingStyle: "atx", // # Heading
hr: "---", // Horizontal rule style
codeBlockStyle: "fenced", // Use ```
bulletListMarker: "-", // Bullet style
});
// Enable GitHub Flavored Markdown (tables, strikethrough, etc.)
turndown.use(gfm);
// Handle <pre><code class="language-xxx"> blocks
turndown.addRule("fencedCodeBlock", {
filter: (node) =>
node.nodeName === "PRE" &&
node.firstChild &&
node.firstChild.nodeName === "CODE",
replacement: (content, node) => {
const className = node.firstChild.getAttribute("class") || "";
const language = (className.match(/language-(\w+)/) || [])[1] || "";
return `\n\n\`\`\`${language}\n${node.firstChild.textContent}\n\`\`\`\n\n`;
},
});
return turndown.turndown(html);
};
export const MarkdownUtils = { markdownToHtml, htmlToMarkdown };
How It Works
1. Markdown → HTML
We use the Unified processor to create a pipeline:
-
remarkParse parses Markdown into an abstract syntax tree (AST).
-
remarkRehype converts the Markdown AST to a HTML AST.
-
rehypeStringify serializes the HTML AST to a string of HTML.
const html = markdownToHtml("# Hello World");
// Output: <h1>Hello World</h1>
2. HTML → Markdown
We use TurndownService, a powerful HTML-to-Markdown converter. To make it even better, we:
- Enable GitHub Flavored Markdown via the gfm plugin.
- Customize code block handling to preserve language syntax highlighting (like language-js).
const markdown = htmlToMarkdown("<h1>Hello</h1>");
// Output: "# Hello"
Example Usage
import { MarkdownUtils } from "./MarkdownUtils";
const md = `
# Sample Title
- List item
- Another item
\`\`\`js
console.log("Hello World");
\`\`\`
`;
const html = MarkdownUtils.markdownToHtml(md);
console.log("HTML Output:\n", html);
const markdownBack = MarkdownUtils.htmlToMarkdown(html);
console.log("Markdown Output:\n", markdownBack);
Use Cases
- Markdown editors
- Static site generators
- Content migration tools
- Developer blogs
- Comment systems (e.g., GitHub-style)
Tips
- Avoid XSS vulnerabilities: Sanitize HTML if you're converting user-generated Markdown.
- Handle edge cases: Some complex HTML might not convert back to perfect Markdown test thoroughly.
- Internationalization: Consider encoding and character set issues if working with multilingual content.