We wanted to start a blog for a long time. We had experiences with Markdown when it came to building blogs. While this is a solution that works for a lot of people, we missed the rich content editing from Notion. Why not build a blog that uses Notion as a CMS? After some research we found the following repository from Vercel. They already did what we wanted: They built a blog using Notion and NextJS. After some more digging, I stumbled on chorale.app, a Notion Page renderer. It takes Notion pages and renders them. These projects are example implementations but they don't contain a wrapped up package that could be easily used. Thats why we created react-notion.
This post was brought to you by Splitbee.io. Splitbee is an all-in-one analytics & conversion tool that simply works and makes your life easier. Give it a try, it's free.
Render Notion pages in React with react-notion
![react-notion is born](https://www.notion.so/image/https%3A%2F%2Fuser-images.githubusercontent.com%2F1440854%2F79684011-6c948280-822e-11ea-9e23-1644903796fb.png?table=block&id=9510b30f-be96-4d2a-b335-2f2a9878292a&cache=v2)
I loved the idea of being able to display Notion content inside React apps. That's why we started building our own renderer, which is now open-source under react-notion. We took inspiration off the projects mentioned above and built a minimal package that can render nearly all block types of Notion.
All you need is to provide a blockMap
to the react-notion Component and it will render the your content.
Access the Notion API with notion-api-worker
![](https://www.notion.so/image/https%3A%2F%2Fuser-images.githubusercontent.com%2F1440854%2F79893752-cc448680-8404-11ea-8d19-e0308eb32028.png?table=block&id=ec935b30-a268-4a8d-9116-0516134e8dc7&cache=v2)
To get the blockMap
, which is the internal data structure of Notion, you would need to to query the complex private Notion API. That's why we created a serverless wrapper. It's based on Cloudflare Workers and due to their caching mechanism we are able to provide best response times all over the world <100ms
Building a simple blog
For this example we are going to use Next.js
, react-notion
, and notion-api-worker
![Example blog setup](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F03416552-fae3-4a2a-9d81-d4e51c5c5474%2FUntitled.png?table=block&id=993f9cd4-b7e9-48c0-baaf-285ed76beffc&cache=v2)
Create a new Notion page with a table database template. You can duplicate this page. Each row represents a single blog post.
Every Notion page has a pageId in the URL. We need it to query all posts later on. For this example we get following id out of the link: 1099525da7e5405c961706de56622ccd
Setup a new Next.js project using the guide provides by Vercel: https://nextjs.org/docs/getting-started and install react-notion to the project.
After you have created your first page in /pages/index.jsx
we will start implementing our blog overview page.
Creating the blog overview page
Let's fetch all blog posts from Notion so we can render a list of them with getStaticProps.
/pages/index.jsx
import Link from "next/link";const NOTION_BLOG_ID = '1099525da7e5405c961706de56622ccd'export const getAllPosts = async () => {return await fetch(`https://notion-api.splitbee.io/v1/table/${NOTION_BLOG_ID}`).then((res) => res.json());}export async function getStaticProps() {const posts = await getAllPosts()return {props: {posts},};}function HomePage({ posts }) {return (<div>{posts.map((post) => (<Link href="/[slug]" as={`/${post.slug}`}><div>{post.title}</div></Link>))}</div>);}export default HomePage
We now successfully implemented the blog overview page
Now we need to create another page to render the content of each blog post.
/pages/[slug].jsx
import { NotionRenderer } from "react-notion";import { getAllPosts } from './'export async function getStaticProps({ params: { slug } }) {// Get all posts againconst posts = await getAllPosts();// Find the current blogpost by slugconst post = posts.find((t) => t.slug === slug);const blocks = await fetch(`https://notion-api.splitbee.io/v1/page/${post.id}`).then((res) => res.json());return {props: {blocks,post,},};}export default ({ post, blocks }) => (<div style={{ maxWidth: 768 }}><h1>{post.title}</h1><NotionRenderer blockMap={blocks} /></div>);
Last, we need to implement getStaticPaths in [slug].jsx
to tell Next.js were to find all blog posts.
export async function getStaticPaths() {const posts = await getAllPosts();return {paths: posts.map((row) => `/${row.slug}`),fallback: true,};}
The only thing missing now are the stylesheets (CSS)
With Next.js we need to import them in a custom _app.jsx
import "react-notion/src/styles.css";import "prismjs/themes/prism-tomorrow.css";export default function MyApp({ Component, pageProps }) {return <Component {...pageProps} />;}
Analytics for your blog
I've spent the last year or so building the best analytics tool possible. Give it a try and let me know what you think of it. It's free with no strings attached.
![Splitbee dashboard —](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F9bfa60af-1704-460a-8ef4-358c9d5e6bb7%2FScreenshot_2020-12-08_at_15.50.07.png?table=block&id=68b0cbc2-dd40-466b-957c-4f9da45a4985&cache=v2)
Getting started with Splitbee is super easy. All you have to do is create an account and add the analytics script tag to your HTML file.
![Sign up page for Splitbee here —](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F735c2f34-ebcd-41e3-9cfc-a7e163aedb5f%2FScreenshot_2020-12-08_at_15.52.14.png?table=block&id=2a4fd8fb-9e9f-45e5-a138-240d74d78e94&cache=v2)
Once you sign up, you should see a script
tag appear on the dashboard. Copy and paste it your next head
section.
import Head from 'next/head'function Main() {return (<div><Head><title>My Blog</title><script async src="https://cdn.splitbee.io/sb.js"></script></Head><p>Hello world!</p></div>)}export default Main
You did it!
Thanks for reading. If you have any questions, feel free to send them my way on Twitter @linstobias.
You can find the full code on Github: https://github.com/splitbee/react-notion-blog