Vue Notion Renderer
Vue-notion is a Vue.js component library designed to render content from Notion pages within a Vue 3 application. It parses Notion's block structure, typically obtained via the Notion API, and translates it into interactive Vue components, enabling developers to display rich text, images, lists, code blocks, and other Notion content types directly in their web apps. The current stable version is 3.0.0, released recently to target lower ES features for broader browser and environment compatibility. While there isn't a strict, regular release cadence, the project receives updates to introduce new features and fix bugs, as evidenced by patches for issues like the `??` operator bug in earlier versions and fixes for empty table rows. Key differentiators include its tight integration with Vue 3's reactivity system, support for custom component overrides via `blockOverrides` to highly customize the rendering of specific Notion block types, and an `imageOptions` API for advanced image handling. It also seamlessly integrates with `@janniks/vue3-katex` for mathematical equation rendering, offering a comprehensive solution for Notion content display.
Common errors
-
Failed to resolve component: NotionRenderer
cause The `NotionRenderer` component was not correctly imported or registered within your Vue application.fixEnsure you have `import { NotionRenderer } from 'vue-notion';` in your script, and it's either globally registered or registered in the `components` option of the parent component, e.g., `{ components: { NotionRenderer } }`. -
TypeError: Cannot read properties of undefined (reading 'call') at Proxy.render (webpack-internal:///./node_modules/@janniks/vue3-katex/dist/index.js)
cause This error often indicates that the `@janniks/vue3-katex` library, a peer dependency, is missing or its styles are not loaded, leading to issues when `vue-notion` attempts to render Notion equation blocks.fixInstall `@janniks/vue3-katex` (`npm install @janniks/vue3-katex`) and add `import '@janniks/vue3-katex/dist/katex.min.css';` to your main application entry point (e.g., `main.js` or `App.vue`'s `<script setup>` or `<style>`).
Warnings
- breaking Version `3.0.0` represents a major version update. While specific API breaking changes are not detailed in the provided release notes, major releases typically include significant internal refactoring, potential API changes, or drops in support for older Vue.js versions or environments. Always perform thorough testing when upgrading from `1.x` to `3.x`.
- gotcha The package has a peer dependency on `@janniks/vue3-katex` for rendering mathematical equations. If `@janniks/vue3-katex` is not installed, or its required CSS (`@janniks/vue3-katex/dist/katex.min.css`) is not imported, Notion equation blocks will not render correctly and may lead to console errors.
- gotcha Early versions of `vue-notion` (prior to `1.5.0`) contained a bug related to the `??` (nullish coalescing) operator, which could cause runtime errors in environments that do not fully support ES2020 features. This was fixed in `1.5.0`.
- gotcha Custom component support via the `blockOverrides` setting was introduced in version `1.4.2`. If you intend to override default Notion block rendering with your own Vue components, you must be on this version or newer.
Install
-
npm install vue-notion -
yarn add vue-notion -
pnpm add vue-notion
Imports
- NotionRenderer
const NotionRenderer = require('vue-notion')import { NotionRenderer } from 'vue-notion'
Quickstart
import { createApp, defineComponent, h } from 'vue';
import { NotionRenderer } from 'vue-notion';
import '@janniks/vue3-katex/dist/katex.min.css'; // Essential for math rendering
// Mock Notion block data (in a real app, this would come from Notion API)
const mockNotionBlocks = [
{ id: '1', type: 'paragraph', paragraph: { rich_text: [{ type: 'text', text: { content: 'Welcome to your Notion page rendered in Vue!' } }] } },
{ id: '2', type: 'heading_2', heading_2: { rich_text: [{ type: 'text', text: { content: 'Key Features:' } }] } },
{ id: '3', type: 'bulleted_list_item', bulleted_list_item: { rich_text: [{ type: 'text', text: { content: 'Render various block types (paragraphs, headings, lists)' } }] } },
{ id: '4', type: 'bulleted_list_item', bulleted_list_item: { rich_text: [{ type: 'text', text: { content: 'Support for images and code blocks' } }] } },
{ id: '5', type: 'code', code: { rich_text: [{ type: 'text', text: { content: 'function hello() { console.log("Vue-Notion"); }' } }], language: 'javascript' } },
{ id: '6', type: 'equation', equation: { expression: 'x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}' } },
{ id: '7', type: 'image', image: { type: 'external', external: { url: 'https://picsum.photos/id/237/200/100' } } },
{ id: '8', type: 'paragraph', paragraph: { rich_text: [{ type: 'text', text: { content: 'Remember to fetch actual Notion data from their API and pass it to the renderer.' } }] } }
];
const App = defineComponent({
components: { NotionRenderer },
data() {
return {
notionPageBlocks: mockNotionBlocks
};
},
template: `
<div id="app" style="font-family: sans-serif; max-width: 800px; margin: 0 auto; padding: 20px;">
<h1>My Notioned Blog Post</h1>
<NotionRenderer :blockMap="notionPageBlocks" fullPage />
</div>
`,
});
createApp(App).mount('#app');