Bidirectional conversion between Notion API blocks, HTML, and Markdown.
- Zero browser dependencies β runs in Node.js and edge runtimes
- No external CSS or JS β HTML output uses only inline styles
- Full coverage of all 34 Notion block types
- Handles any HTML β not just Notion-generated markup
npm install notion-markupUse it directly with npx β no install required:
npx notion-markup <operation> [options]| Operation | Description |
|---|---|
notion-to-html |
Convert Notion blocks JSON to HTML |
notion-to-markdown |
Convert Notion blocks JSON to Markdown |
html-to-notion |
Convert HTML to Notion blocks JSON |
html-to-markdown |
Convert HTML to Markdown |
markdown-to-html |
Convert Markdown to HTML |
markdown-to-notion |
Convert Markdown to Notion blocks JSON |
| Flag | Description |
|---|---|
-i, --input <string> |
Pass input as a string argument |
-f, --file <path> |
Read input from a file |
| (stdin) | Pipe input via stdin |
-h, --help |
Show help |
# Pipe via stdin
echo '<h1>Hello</h1>' | npx notion-markup html-to-markdown
# Inline input
npx notion-markup markdown-to-html -i "# Hello"
# From file
npx notion-markup html-to-notion -f page.html
# Chain conversions
cat blocks.json | npx notion-markup notion-to-html | npx notion-markup html-to-markdownimport {
notionToHtml,
htmlToNotionBlocks,
notionToMarkdown,
markdownToNotionBlocks,
htmlToMarkdown,
markdownToHtml,
} from "notion-markup";
// Notion blocks β HTML
const html = notionToHtml(blocks);
// HTML β Notion blocks
const blocks = htmlToNotionBlocks(html);
// Notion blocks β Markdown
const md = await notionToMarkdown(blocks);
// Markdown β Notion blocks
const blocks = await markdownToNotionBlocks(md);
// HTML β Markdown (standalone)
const md = await htmlToMarkdown(html);
const html = await markdownToHtml(md);Converts an array of Notion API block objects into an HTML string (body content only, no <html> or <head> wrapper).
Returns inline-styled HTML with no external CSS or JavaScript dependencies.
Parses an HTML string and returns an array of Notion API block objects. Handles all standard HTML5 tags, not just Notion-generated HTML.
Converts Notion blocks to GFM-compatible Markdown. Internally converts to HTML first, then to Markdown via the unified ecosystem.
Parses a Markdown string and returns Notion API block objects. Supports GFM extensions (tables, strikethrough, task lists).
Direct HTML β Markdown conversion using rehype-remark.
Direct Markdown β HTML conversion using remark-rehype.
| Notion Block Type | HTML Output |
|---|---|
paragraph |
<p> with rich text tags |
heading_1 |
<h1> |
heading_2 |
<h2> |
heading_3 |
<h3> |
heading_* (toggleable) |
<details><summary><h*> |
bulleted_list_item |
<ul><li> (auto-grouped) |
numbered_list_item |
<ol><li> (auto-grouped) |
to_do |
<ul><li class="to-do"><input type="checkbox"> |
toggle |
<details><summary> |
quote |
<blockquote> |
callout |
<div class="callout"> with icon + background color |
code |
<pre><code class="language-*"> |
equation |
<div class="equation" data-expression="..."> |
divider |
<hr/> |
image |
<figure><img> with optional <figcaption> |
video |
<figure><video controls> |
audio |
<audio controls> |
file |
<a href="..." class="file-download"> |
pdf |
<figure><iframe> |
embed |
<figure><iframe> |
bookmark |
<a class="bookmark"> |
link_preview |
<a class="link-preview"> |
table |
<table> with <thead>/<tbody> |
table_row |
<tr> with <th> or <td> |
column_list |
<div class="column-list" style="display:flex"> |
column |
<div class="column" style="width:..."> |
synced_block |
Renders children directly |
table_of_contents |
<nav class="table-of-contents"> |
breadcrumb |
<nav class="breadcrumb"> |
child_page |
<div class="child-page"><a> |
child_database |
<div class="child-database"> |
template |
<div class="template"> |
link_to_page |
<a class="link-to-page"> |
unsupported |
<!-- unsupported block --> |
| HTML Element | Notion Block Type |
|---|---|
<h1> |
heading_1 |
<h2> |
heading_2 |
<h3> |
heading_3 |
<h4>, <h5>, <h6> |
heading_3 (downgraded) |
<p> |
paragraph |
<ul><li> |
bulleted_list_item |
<ol><li> |
numbered_list_item |
<li> with checkbox |
to_do |
<blockquote> |
quote |
<pre><code> |
code |
<hr> |
divider |
<img> |
image |
<video> |
video |
<audio> |
audio |
<iframe> |
embed |
<table> |
table + table_row |
<details><summary> |
toggle or toggleable heading |
<a class="bookmark"> |
bookmark |
<div class="callout"> |
callout |
<div class="equation"> |
equation |
<div class="column-list"> |
column_list + column |
<nav class="table-of-contents"> |
table_of_contents |
<div class="child-page"> |
child_page |
<div class="child-database"> |
child_database |
| Annotation | HTML Render | HTML Parse |
|---|---|---|
bold |
<strong> |
<strong>, <b> |
italic |
<em> |
<em>, <i>, <cite>, <dfn>, <var> |
strikethrough |
<s> |
<s>, <del>, <strike> |
underline |
<u> |
<u>, <ins> |
code |
<code> |
<code>, <kbd>, <samp> |
color (text) |
<span style="color:..."> |
<span style="color:..."> |
color (background) |
<span style="background-color:..."> |
<span style="background-color:..."> |
| β | β | <mark> β yellow_background |
Tags not native to Notion are intelligently mapped:
| HTML Tag | Behavior |
|---|---|
<section>, <article>, <aside>, <main>, <header>, <footer>, <nav>, <div> |
Recurse into children |
<dl> |
<dt> β bold bulleted item, <dd> β indented paragraph |
<address> |
Italic paragraph |
<picture> |
Extracts <img> fallback |
<figure> |
Extracts inner media element |
<abbr>, <time>, <small>, <sub>, <sup>, <q>, <span> |
Pass through as plain text |
<svg>, <canvas>, <form>, <script>, <style> |
Skipped |
All 19 Notion colors are supported with bidirectional hex mapping:
| Color | Hex (text) | Background variant |
|---|---|---|
blue |
#337EA9 |
blue_background β #D3E5EF |
brown |
#9F6B53 |
brown_background β #E9DFDA |
gray |
#787774 |
gray_background β #EBECED |
green |
#448361 |
green_background β #DBEDDB |
orange |
#D9730D |
orange_background β #FADEC9 |
pink |
#C14C8A |
pink_background β #F5E0E9 |
purple |
#9065B0 |
purple_background β #E8DEEE |
red |
#D44C47 |
red_background β #FFE2DD |
yellow |
#CB912F |
yellow_background β #FDE4AC |
All types are fully exported:
import type {
Block,
RichText,
RichTextText,
RichTextMention,
RichTextEquation,
Annotations,
Color,
FileObject,
Icon,
TextBlockContent,
HeadingContent,
ToDoContent,
CodeContent,
CalloutContent,
EquationContent,
BookmarkContent,
EmbedContent,
TableContent,
TableRowContent,
ColumnListContent,
ColumnContent,
SyncedBlockContent,
LinkToPageContent,
NumberedListItemContent,
TableOfContentsContent,
} from "notion-markup";Notion Blocks βββ notionToHtml() βββ HTML
β
ββββ htmlToMarkdown() βββ Markdown
β
ββββ htmlToNotionBlocks() βββ Notion Blocks
Markdown βββ markdownToHtml() βββ HTML βββ htmlToNotionBlocks() βββ Notion Blocks
Composed pipelines:
notionToMarkdown()=notionToHtml()βhtmlToMarkdown()markdownToNotionBlocks()=markdownToHtml()βhtmlToNotionBlocks()
The HTMLβMarkdown conversions use the unified ecosystem (rehype-remark, remark-rehype, remark-gfm).
MIT