Overview
The site uses a custom parser (src/lib/notion-parse.ts) that converts Notion’s block-based content into Markdown and HTML. This allows you to write content in Notion’s familiar editor and have it automatically formatted for your website.
Parsing Flow
parse() at src/lib/notion-parse.ts:130-314, which recursively processes blocks and their children.
Text Formatting
Rich Text Annotations
Notion’s text formatting is converted to HTML tags (src/lib/notion-parse.ts:77-104):
| Notion | Markdown/HTML | Example |
|---|---|---|
| Bold | <b>text</b> | bold text |
| Italic | <i>text</i> | italic text |
| Underline | <u>text</u> | underlined |
<s>text</s> | ||
Code | <code>text</code> | inline code |
| Links | [text](url) | example link |
Combined Styles
Multiple styles can be combined:Text Colors
Notion’s color options are converted to Tailwind CSS classes (src/lib/notion-parse.ts:12-71):
| Notion Color | CSS Class | Use Case |
|---|---|---|
| Gray | !text-gray-500 | Muted text |
| Brown | !text-stone-500 | Earthy tones |
| Orange | !text-orange-500 | Warnings, highlights |
| Yellow | !text-yellow-500 | Cautions, notes |
| Green | !text-green-500 | Success, positive |
| Blue | !text-blue-500 | Links, info |
| Purple | !text-purple-500 | Special content |
| Pink | !text-pink-500 | Accents |
| Red | !text-red-500 | Errors, important |
Background Colors
Background variants use similar classes:Block Types
Paragraphs
Notion: Regular text paragraphsConverted to: Plain text with formatting
src/lib/notion-parse.ts:144-156
Empty paragraphs are converted to
<br /> tags to preserve spacing.Headings
Notion: Heading 1, Heading 2, Heading 3Converted to: Markdown headings
src/lib/notion-parse.ts:157-162
Lists
Bulleted Lists
Numbered Lists
1. - Markdown auto-numbers them.
To-Do Lists
src/lib/notion-parse.ts:163-181
Quotes
Notion: Quote blockConverted to: Markdown blockquote
src/lib/notion-parse.ts:167-174
Code Blocks
Notion: Code block with languageConverted to: Fenced code block
src/lib/notion-parse.ts:193-201
Callouts
Notion: Callout blockConverted to: Code block (temporary)
Callout text with icon
Callout rendering is currently basic. Future versions may use custom components for better styling.
src/lib/notion-parse.ts:202-210
Toggles
Notion: Toggle/disclosure blockConverted to: HTML
<details> element
src/lib/notion-parse.ts:182-189
Dividers
Notion: Divider blockConverted to: Markdown horizontal rule
src/lib/notion-parse.ts:211-212
Media Blocks
Images
Notion: Image blockConverted to: Astro
<Image> component with optimization
Images are downloaded to src/assets/ during sync and referenced with dimensions:
- Automatic download during sync (
src/lib/notion-cms-asset.ts:16-58) - Dimension detection via
probe-image-size - WebP conversion for optimization
- Alt text from Notion caption
src/lib/notion-parse.ts:222-236
Videos
Notion: Video blockConverted to: HTML5
<video> element
src/lib/notion-parse.ts:237-242
Audio
Notion: Audio blockConverted to: HTML5
<audio> element
src/lib/notion-parse.ts:263-268
PDFs
Notion: PDF embedConverted to: Embedded PDF viewer
src/lib/notion-parse.ts:243-260
Embeds
Notion: Embed block (YouTube, etc.)Converted to: Markdown link
src/lib/notion-parse.ts:217-221
Bookmarks
Notion: Bookmark or link previewConverted to: Quoted link
src/lib/notion-parse.ts:269-275
Tables
Notion: Table blockConverted to: HTML table
- First row as header (if enabled in Notion)
- First column styling (if enabled in Notion)
- Automatic HTML table generation
src/lib/notion-parse.ts:276-300
Unsupported Blocks
These block types are not currently rendered (src/lib/notion-parse.ts:302-312):
- Breadcrumb
- Column list / Column
- Link to page
- Template
- Synced block
- Child page
- Child database
- File (non-media files)
- Table of contents (returns empty string)
Nested Blocks
Blocks can have children, which are automatically processed recursively:src/lib/notion-parse.ts:136-140).
Special Characters
Less-than signs (<) are escaped to prevent HTML injection:
src/lib/notion-parse.ts:85
Asset Handling
Media assets (images, videos, PDFs) are handled specially:Download
getAssetUrl() downloads the file from Notion to local storage (src/lib/notion-cms-asset.ts).Asset Filename Format
file.abc123def456.png
This ensures unique filenames and allows for incremental updates.
Equations
Notion: Equation blockConverted to: Plain text (currently)
Future versions may support LaTeX rendering using a library like KaTeX.
src/lib/notion-parse.ts:190-192
Writing Notion Content
Best Practices
Use semantic headings
Use semantic headings
Structure your content with Heading 1 for main sections, Heading 2 for subsections, etc. This improves SEO and accessibility.
Add alt text to images
Add alt text to images
Use Notion’s caption feature for images. This becomes the alt text in the rendered HTML.
Test formatting locally
Test formatting locally
Run
pnpm dev to see how your Notion content renders before publishing.Use code blocks with language
Use code blocks with language
Select the programming language in Notion’s code block settings for proper syntax highlighting.
Avoid unsupported blocks
Avoid unsupported blocks
Don’t rely on breadcrumbs, columns, or other unsupported blocks for critical content.
Content Workflow
Extending the Parser
To add support for new block types or modify existing ones:- Locate the parser:
src/lib/notion-parse.ts - Find the switch statement: Line 143
- Add a new case:
- Handle children if needed:
- Test thoroughly:
Troubleshooting
Block not rendering
Check:- Block type is supported (see unsupported blocks list)
- No parsing errors in build logs
- Content appears in generated MDX file
Formatting lost
Check:- Rich text annotations are applied in Notion
- Tailwind classes are available in your CSS
proseclass is applied to the container element
Images not loading
Check:- Image was downloaded to
src/assets/ - File permissions allow reading
- MDX file has correct import statement
- Notion image block (not just a link to an image)
Tables rendering incorrectly
Check:- Table is created as a Notion table block (not a database)
- Header row/column settings in Notion
- CSS styles for
<table>elements
Performance Considerations
- Recursive parsing: Nested blocks are processed recursively, which can be slow for deeply nested content
- Asset downloads: Images and media are downloaded once and cached based on block ID
- Incremental sync: Only changed content is re-parsed (via
lastEditedTimecheck) - Build-time only: Parsing happens once during build, not on every page load
Related Resources
- Parser implementation:
src/lib/notion-parse.ts - Asset handling:
src/lib/notion-cms-asset.ts - Block fetching:
src/lib/notion-cms.ts - Notion API docs: https://developers.notion.com/reference/block