Skip to content

About

πŸ—’οΈ Bidirectional conversion between Notion API blocks, HTML, and Markdown

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

notion-markup

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

Installation

npm install notion-markup

CLI

Use it directly with npx β€” no install required:

npx notion-markup <operation> [options]

Operations

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

Input methods

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

Examples

# 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-markdown

Quick Start

import {
  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);

API Reference

notionToHtml(blocks: Block[]): string

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.

htmlToNotionBlocks(html: string): Block[]

Parses an HTML string and returns an array of Notion API block objects. Handles all standard HTML5 tags, not just Notion-generated HTML.

notionToMarkdown(blocks: Block[]): Promise<string>

Converts Notion blocks to GFM-compatible Markdown. Internally converts to HTML first, then to Markdown via the unified ecosystem.

markdownToNotionBlocks(markdown: string): Promise<Block[]>

Parses a Markdown string and returns Notion API block objects. Supports GFM extensions (tables, strikethrough, task lists).

htmlToMarkdown(html: string): Promise<string>

Direct HTML β†’ Markdown conversion using rehype-remark.

markdownToHtml(markdown: string): Promise<string>

Direct Markdown β†’ HTML conversion using remark-rehype.

Notion Block β†’ HTML Mapping

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 β†’ Notion Block Mapping

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

Rich Text Annotations

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

Extra HTML Tags Handling

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

Notion Color Support

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

TypeScript Types

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";

How It Works

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).

License

MIT

About

πŸ—’οΈ Bidirectional conversion between Notion API blocks, HTML, and Markdown

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages