Convert HTML To Notion Blocks

Valentsea
Total
0
Shares

If you need to import HTML into Notion, you may have faced the challenge of converting HTML to Notion’s block format. In my recent project, I stumbled upon this issue and was unable to find any existing package that provided a solution. That is why in this post I want to share the code and libraries that helped me make it work.

The first step is to parse the HTML code into a JavaScript object. To do this, we use the fromHtml function from the hast-util-from-html library, which takes an HTML string as input and returns a hast object:

import { fromHtml } from 'hast-util-from-html';

const html = '

Hello world!

'; // HTML to HTML AST const hast = fromHtml(html, { fragment: true });
Enter fullscreen mode

Exit fullscreen mode

The hast object represents the HTML code as an abstract syntax tree (AST) that can be manipulated and transformed into other formats:

{
  type: 'root',
  children: [
    {
      type: 'element',
      tagName: 'h1',
      properties: {},
      children: [
        {
          type: 'text',
          value: 'Hello ',
          position: {
            start: { line: 1, column: 5, offset: 4 },
            end: { line: 1, column: 11, offset: 10 }
          }
        },
        {
          type: 'element',
          tagName: 'strong',
          properties: {},
          children: [
            {
              type: 'text',
              value: 'world!',
              position: {
                start: { line: 1, column: 19, offset: 18 },
                end: { line: 1, column: 25, offset: 24 }
              }
            }
          ],
          position: {
            start: { line: 1, column: 11, offset: 10 },
            end: { line: 1, column: 34, offset: 33 }
          }
        }
      ],
      position: {
        start: { line: 1, column: 1, offset: 0 },
        end: { line: 1, column: 39, offset: 38 }
      }
    }
  ],
  data: { quirksMode: false },
  position: {
    start: { line: 1, column: 1, offset: 0 },
    end: { line: 1, column: 39, offset: 38 }
  }
}
Enter fullscreen mode

Exit fullscreen mode

Once the HTML code is parsed into a hast object, the next step is to convert it to Markdown. We use the toMdast function from the hast-util-to-mdast library, which takes a hast object as input and returns a mdast object.

import { fromHtml } from 'hast-util-from-html';
import { toMdast } from 'hast-util-to-mdast';

const html = '

Hello world!

'; const hast = fromHtml(html, { fragment: true }); // HTML AST to Markdown AST const mdast = toMdast(hast);
Enter fullscreen mode

Exit fullscreen mode

The mdast object represents the Markdown code as an AST, similar to the previous HTML AST:

{
  type: 'root',
  children: [
    {
      type: 'heading',
      depth: 1,
      children: [
        {
          type: 'text',
          value: 'Hello ',
          position: {
            start: { line: 1, column: 5, offset: 4 },
            end: { line: 1, column: 11, offset: 10 }
          }
        },
        {
          type: 'strong',
          children: [
            {
              type: 'text',
              value: 'world!',
              position: {
                start: { line: 1, column: 19, offset: 18 },
                end: { line: 1, column: 25, offset: 24 }
              }
            }
          ],
          position: {
            start: { line: 1, column: 11, offset: 10 },
            end: { line: 1, column: 34, offset: 33 }
          }
        }
      ],
      position: {
        start: { line: 1, column: 1, offset: 0 },
        end: { line: 1, column: 39, offset: 38 }
      }
    }
  ],
  position: {
    start: { line: 1, column: 1, offset: 0 },
    end: { line: 1, column: 39, offset: 38 }
  }
}
Enter fullscreen mode

Exit fullscreen mode

The next step is to serialize Markdown AST into a Markdown string. We use the toMarkdown function from the mdast-util-to-markdown library, which takes a mdast object as input and returns Markdown string:

import { fromHtml } from 'hast-util-from-html';
import { toMdast } from 'hast-util-to-mdast';
import { toMarkdown } from 'mdast-util-to-markdown';

const html = '

Hello world!

'; const hast = fromHtml(html, { fragment: true }); const mdast = toMdast(hast); // Markdown AST to Markdown string const markdown = toMarkdown(mdast);
Enter fullscreen mode

Exit fullscreen mode

The Markdown string has the format we are used to from Editors like on Dev.to or GitHub:

# Hello **world!**
Enter fullscreen mode

Exit fullscreen mode

The final step is to convert the Markdown string into Notion block objects that can be used to create new blocks using the Notion API. We use the markdownToBlocks function from the @tryfabric/martian library, which takes the Markdown string as input and returns an array of BlockObjectRequest objects:

import { fromHtml } from 'hast-util-from-html';
import { toMdast } from 'hast-util-to-mdast';
import { toMarkdown } from 'mdast-util-to-markdown';
import { markdownToBlocks } from '@tryfabric/martian';

const html = '

Hello world!

'; const hast = fromHtml(html, { fragment: true }); const mdast = toMdast(hast); const markdown = toMarkdown(mdast); // Markdown string to Notion Blocks const blocks = markdownToBlocks(markdown);
Enter fullscreen mode

Exit fullscreen mode

Each BlockObjectRequest object represents a Notion block and contains the necessary information to create and format the block in your Notion page:

[
  {
    object: 'block',
    type: 'heading_1',
    heading_1: {
      rich_text: [
        {
          type: 'text',
          annotations: {
            bold: false,
            strikethrough: false,
            underline: false,
            italic: false,
            code: false,
            color: 'default'
          },
          text: { content: 'Hello ', link: undefined }
        },
        {
          type: 'text',
          annotations: {
            bold: true,
            strikethrough: false,
            underline: false,
            italic: false,
            code: false,
            color: 'default'
          },
          text: { content: 'world!', link: undefined }
        }
      ]
    }
  }
]
Enter fullscreen mode

Exit fullscreen mode

Here is an example of how to create a new page in your Notion workspace with the blocks converted from the original HTML. We use the @notionhq/client library and you’ll need to have a valid Notion API key and database ID:

import { Client } from '@notionhq/client';

// ...
const blocks = markdownToBlocks(markdown);

const notion = new Client({ auth: process.env.NOTION_API_KEY });

const properties = {
  Name: {
    title: [{ text: { content: 'New Page' } }]
  }
};

const response = await notion.pages.create({
  parent: { database_id: process.env.NOTION_DATABASE_ID },
  properties,
  children: blocks,
});
Enter fullscreen mode

Exit fullscreen mode

The response from Notion contains the new page and its properties. However, it does not contain the blocks, since these must be queried separately.

{
  object: 'page',
  id: 'c7d50cb4-0518-4ef9-8457-056a53fd53eb',
  created_time: '2023-03-01T10:28:00.000Z',
  last_edited_time: '2023-03-01T10:28:00.000Z',
  created_by: { object: 'user', id: '9d72c6df-be87-4bb5-8edb-1c19461d01bb' },
  last_edited_by: { object: 'user', id: '9d72c6df-be87-4bb5-8edb-1c19461d01bb' },
  cover: null,
  icon: null,
  parent: {
    type: 'database_id',
    database_id: '95970798-23cc-4f7c-a0c5-4870b80fcdee'
  },
  archived: false,
  properties: {
    Name: {
      id: 'title',
      type: 'title',
      title: [
        {
          type: 'text',
          text: { content: 'New Page', link: null },
          annotations: {
            bold: false,
            italic: false,
            strikethrough: false,
            underline: false,
            code: false,
            color: 'default'
          },
          plain_text: 'New Page',
          href: null
        }
      ]
    },
    // ...
  },
  url: 'https://www.notion.so/New-Page-c7d50cb405184ef98457056a53fd53eb'
}
Enter fullscreen mode

Exit fullscreen mode


I hope you found this post helpful. If you have any questions or comments, feel free to leave them below. If you’d like to connect with me, you can find me on LinkedIn or GitHub. Thanks for reading!

Total
0
Shares
Valentsea

Usability Testing: The Key to Creating User-Friendly and Effective Products

Usability testing is the process of evaluating a product, service, or system by testing it with representative users.…

You May Also Like