Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/9gustin/react-notion-render
A library to render notion pages
https://github.com/9gustin/react-notion-render
notion notion-react react
Last synced: 2 days ago
JSON representation
A library to render notion pages
- Host: GitHub
- URL: https://github.com/9gustin/react-notion-render
- Owner: 9gustin
- License: mit
- Created: 2021-05-15T15:22:45.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-11-24T23:45:25.000Z (3 months ago)
- Last Synced: 2025-02-02T08:27:56.717Z (9 days ago)
- Topics: notion, notion-react, react
- Language: TypeScript
- Homepage:
- Size: 2.76 MB
- Stars: 148
- Watchers: 2
- Forks: 21
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE.md
Awesome Lists containing this project
README
React Notion Render
A library to render notion pages
[![NPM](https://img.shields.io/npm/v/@9gustin/react-notion-render.svg)](https://www.npmjs.com/package/@9gustin/react-notion-render)
![npm](https://img.shields.io/npm/dw/@9gustin/react-notion-render)
![PR](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)
![Stars](https://img.shields.io/github/stars/9gustin/react-notion-render.svg?style=social)## Table of contents
- [Description](#description)
- [Installation](#installation)
- [Examples](#examples)
- [Basic example](#basic-example)
- [Blog with Notion as CMS](#blog-with-notion-as-cms)
- [Notion page to single page](#notion-page-to-single-page)
- [Usage](#usage)
- [Override built-in components (new)](#override-built-in-components-new)
- [Giving Styles](#giving-styles)
- [...moreProps](#moreprops)
- [Custom Components](#custom-components)
- [Display a custom table of contents](#display-a-custom-table-of-contents)
- [Guides](#guides)
- [How to use code blocks](https://github.com/9gustin/react-notion-render/wiki/About-code-blocks-and-how-to-colorize-it-%F0%9F%8E%A8)
- [Supported blocks](#supported-blocks)
- [Contributions](#contributions)## Description
When we want to [retrieve the content of a Notion page](https://developers.notion.com/docs/working-with-page-content), using the Notion API we will obtain a complex block structure(like [this example](https://github.com/9gustin/react-notion-render/blob/main/dev-example/data/blocks.json)). This package solves that structure and takes care of rendering that response.
## Installation
```bash
npm i @9gustin/react-notion-render
```## Examples
### Basic example
I would use the package [@notionhq/client](https://www.npmjs.com/package/@notionhq/client) to get data from the Notion API and take this example of [Notion Service](https://github.com/samuelkraft/notion-blog-nextjs/blob/master/lib/notion.js) also you can fetch the data from the api. This example take pages of an database an render the first of list. This example is an Page in Next.js.```jsx
import { Render } from '@9gustin/react-notion-render'
import { getBlocks, getDatabase } from '../services/notion'export default ({blocks}) =>
export const getStaticProps = async () => {
const DATABASE_ID = '54d0ff3097694ad08bd21932d598b93d'
const database = await getDatabase(DATABASE_ID)
const blocks = await getBlocks(database[0].id)return {
props: {
blocks
}
}
}
```### Blog with Notion as CMS
I've maded a template to blog page, that use this package and allows you have a blog using notion as CMS.
📎 Repo: [@9gustin/notion-blog-nextjs](https://github.com/9gustin/notion-blog-nextjs)
📚 Notion Database: [notion/notion-blog-nextjs](https://9gustin.notion.site/a30378a9a7a74a398a17b733136a70d4?v=db951035b8c44968ae226f2c2d358529)
✨Web: [blog-template](https://blog-template.9gustin.com)**Note**: My personal blog now it's using this template. Url: [9gustin.com](https://9gustin.com)
### Notion page to single page
This example it's not maded by me, but i show you what package can do. This is a single page which use this package to render content
📎 Repo: [sasigume/notion-to-next-single-page](https://github.com/sasigume/notion-to-next-single-page)## Usage
### Override built-in components (new)
You can override the package components, for example, if you want to use your own Code component or to replace nativefor NextImage. For this you have the prop `blockComponentsMapper`.
This works to use your own styles, a library of components (like Chackra UI, ANT Design) or better components than natives.
For example, if you want to use a custom H1:
```JSX
const MyHeading = ({plainText}) => {
returnH1! {plainText}
}
```And in the render you pass the prop `blockComponentsMapper` like:
```JSX```
### How works?
**blockComponentsMapper**
It prop receives an json of type BlockComponentsMapperType, the keys represents the notion type:
https://github.com/9gustin/react-notion-render/blob/154e094e9477b5dada03358e2cecf695c06bb4d3/src/constants/BlockComponentsMapper/types.tsAnd here the notion types enum(you can import it):
https://github.com/9gustin/react-notion-render/blob/feature/customBlockMapper/src/types/BlockTypes.ts**withContentValidation**
I recommend that you import withContentValidation HOC from the package and wrap component on it, this HOC parse props and make it more clean, here the font-code:
https://github.com/9gustin/react-notion-render/blob/154e094e9477b5dada03358e2cecf695c06bb4d3/src/hoc/withContentValidation/index.tsx
I must work on a more clear documentation about this prop, but for now you can explore it.
### Mapping page url
In Notion, page IDs are used to link between Notion pages. For example, if you link to a Notion page titled "Test" at `notion.so/test-1a2b3c4d`, the underlying markup will look like this:
```HTML
```When building a website from Notion content, you may use a different logic for creating paths to access those Notion pages. For example, the page above may now be available at `/test` path. To rewrite `/1a2b3c4d` to `/test`, you can define your own function for mapping url and pass it to prop `mapPageUrlFn` of the Render component.
### Giving styles
If you followed the [basic example](#basic-example), you may notice that the page are rendered without styles, only pure text. To solve that we can use the Render props, like the following cases.#### Using default styles
This package give you default styles, colors, text styles(blod, italic) and some little things, if you want use have to add two things:First import the stylesheet
```jsx
import '@9gustin/react-notion-render/dist/index.css'
```
And then add to the Render the prop **useStyles**, like that:
```jsx```
And it's all, now the page looks some better, i tried to not manipulate that styles so much to preserve generic styles.
#### Using your own styles
If you want to add styles by your own, you can use the prop **classNames**, this props gives classes to the elements, it make more easier to identify them. For example to paragraphs give the class "rnr-paragraph", and you can add this class in your CSS and give styles.```jsx
```
This is independient to the prop **useStyles**, you can combinate them or use separated.**Components Reference**
| ClassName | Notion Reference | HTML Tag |
| ------------------ | ------------------- | ------------------------------------------------ |
| rnr-heading_1 | Heading 1 | h1 |
| rnr-heading_2 | Heading 2 | h2 |
| rnr-heading_3 | Heading 3 | h3 |
| rnr-paragraph | Paragraph | p |
| rnr-to_do | To-do List | ul |
| rnr-bulleted_list_item | Bulleted List | ul |
| rnr-numbered_list_item | Numered List | ol |
| rnr-toggle | Toggle List | ul |
| rnr-image | Image | a |
| rnr-video | Video | external: **iframe**, notion uploaded video: **video** |
| rnr-file | File | a |
| rnr-embed | Embed | iframe |
| rnr-pdf | PDF | iframe |
| rnr-callout | Callout | div |
| rnr-quote | Quote | blockquote |
| rnr-divider | Divider | hr |
| rnr-code | Code | pre > code |
| rnr-table_of_contents | Table of contents | ul |
| rnr-table | Table | table |
| rnr-table_row | Table row | tr |**Text Styles**
| ClassName | Notion Reference |
| ------------------ | ------------------- |
| rnr-bold | Bold |
| rnr-italic | Italicize |
| rnr-strikethrough | Strike Through |
| rnr-underline | Underline |
| rnr-inline-code | Code |**Text colors**
| ClassName | HEX |
| ------------------ | --- |
| rnr-red | #ff2525 |
| rnr-gray | #979797 |
| rnr-brown | #816868 |
| rnr-orange | #FE9920 |
| rnr-yellow | #F1DB4B |
| rnr-green | #22ae65 |
| rnr-purple | #a842ec |
| rnr-pink | #FE5D9F |
| rnr-blue | #0eb7e4 |### ...moreProps
The Render component has two more props that you can use.#### Custom title url
With this package you can pin the titles in the url to share it. For example, if you have a title like **My Title** and you click it, the url looks like **url.com#my-title**. The function that parse the text it's [here](https://github.com/9gustin/react-notion-render/blob/main/src/utils/slugify.ts), you can check it. But if you want some diferent conversion you can pass a custom slugify function. In case that you want to separate characthers by _ instead of - yo can pass the **slugifyFn** prop:
```jsx
text.replace(/[^a-zA-Z0-9]/g,'_')} />
```
Or whatever you want, slugifyFn should receive and return a string.
If you dont want this functionality you can disable it with the prop **simpleTitles**:
```jsx```
#### Preserve empty blocks
Now by default the Render component discard the empty blocks that you put in your notion page. If you want to preserve you can pass the prop **emptyBlocks** and it be rendered.
```jsx```
The empty blocks contain the class "**rnr-empty-block**", this class has default styles (with **useStyles**) but you can apply your own styles.
### Custom components
Now Notion API only supports text blocks, like h1, h2, h3, paragraph, lists([Notion Doc.](https://developers.notion.com/reference/block)). Custom components are here for you, it allows you to use other important blocks.**Important**
The text to custom components sould be plain text, when you paste a link in Notion he convert to a link. You should convert it to plain text with the "Remove link" button. Like there:
![image](https://user-images.githubusercontent.com/38046239/122657679-46bd8300-d13c-11eb-9736-8c67e81a9ba7.png)#### Link
Now you can use links like Markdown, links are supported by Notion API, but this add the possibility to made autorreference links, as an index.**Example:**
```
Index:
[1. Declarative](#declarative)
[2. Component Based](#component-based)
[3. About React](#about-react)
```
The link be maded with the slugifyFn, you can [check the default](https://github.com/9gustin/react-notion-render/blob/main/src/utils/slugify.ts), or [pass a custom](#custom-title-url).### Image
⚠️ **Now we support native notion images**, if you add a image in your notion page this package would render it ;). This option would not be deprecated, just a suggestion.This it simple, allows you to use images(includes GIF's). The syntax are the same like [Markdown images](https://www.digitalocean.com/community/tutorials/markdown-markdown-images). For it you have to include next text into your notion page as simple text
**Example:**
```
![My github profile pic](https://avatars.githubusercontent.com/u/38046239)
```**Plus**
Also you can add a link to image, like an image anchor. This link would be opened when the user click the image. Thats works adding an # with the link after the markdown image.
```
![My github profile pic](https://avatars.githubusercontent.com/u/38046239)#https://github.com/9gustin
```
So when the user click my image in the blog it will be redirected to my github profile.### Video
⚠️ **Now we support native notion videos**, if you add a video in your notion page this package would render it ;). This option would not be deprecated, just a suggestion
You can embed Videos. You have 3 ways to embed a video.- Local
- Youtube
- Google Drive (with a public share url)**Structure:**
```
-[title, or alternative text](url)
```**Example:**
```
-[my youtube video](https://youtu.be/aA7si7AmPkY)
```### Display a custom table of contents
Now we exporting the **indexGenerator** function, with that you can show a table of contents of your page content. This function receive a list of blocks and return only the title blocks. The structure of the result it's like:
![image](https://user-images.githubusercontent.com/38046239/129499362-28448241-3bf9-47b7-8629-d40d7e90a447.png)
you can use it like that:
```jsx
import { indexGenerator, rnrSlugify } from '@9gustin/react-notion-render'const TableOfContents = ({blocks}) => {
return (
<>
Table of contents:
-
{plainText} - {type}
{
indexGenerator(blocks).map(({ id, plainText, type }) => (
))
}
>
)
}
export default TableOfContents
```
if you want to add links use **rnrSlugify** or your [custom slugify function](#custom-title-url) to generate the href.
## Guides
### How to use code blocks
Checkout in this repo wiki:
https://github.com/9gustin/react-notion-render/wiki/About-code-blocks-and-how-to-colorize-it-%F0%9F%8E%A8
## Supported blocks
Most common block types are supported. We happily accept pull requests to add support for the missing blocks.
| Block | Supported |
|---------|-------------|
| Text | ✅ |
| Heading | ✅ |
| Image | ✅ |
| Image Caption | ✅ |
| Bulleted List | ✅ |
| Numbered List | ✅ |
| Quote | ✅ |
| Callout | ✅ |
| iframe | ✅ |
| Video | ✅ |
| File | ✅ |
| Divider | ✅ |
| Link | ✅ |
| Code | ✅ |
| Toggle List | ✅ |
| Page Links | ✅ |
| Checkbox | ✅ (read-only) |
| Table Of Contents | ✅ |
| Table | ✅ |
| Synced blocks | ✅ |
| Web Bookmark | ❌ |
## Contributions:
If you find a bug, or want to suggest a feature you can create a [New Issue](https://github.com/9gustin/react-notion-render/issues/new) and will be analized. **Contributions of any kind welcome!**
### Running the dev example
In the repo we have a dev example, with this you can test what you are developing.
Clone repo and install package dependencies
```BASH
git clone https://github.com/9gustin/react-notion-render.git
cd react-notion-render
npm install
```
Run dev example to test added features. The example are in next.js, so have to install this dependency into dev-example folder.
**IMPORTANT:** Install dependencies of dev-example with `npm install`, not with `yarn`. This is because the dev-example uses parent node_modules (with file:../node_modules) and if install it with yarn it has problems with sub dependencies.
```BASH
cd dev-example
npm install
```
Add .env file with your notion token and run the example.
Inside of dev-example folder you find a .env.example file with the structure of .env file. Steps:
1. Go to [notion.so/my-integrations](https://www.notion.so/my-integrations) and generate a new integration, copy the `Internal Integration Token` and paste it into the .env file wit the key `NOTION_TOKEN`.
2. Go to your notion, create a database that you want to use as example. Enter in it and copy the database id from url. `https://www.notion.so/YOUR_PROFILE/DATABASE_ID?v=RANDOM`
3. Share the database with the integration.
More detail in [developers.notion.com/docs/getting-started](https://developers.notion.com/docs/getting-started)
Starting the dev example
To run the dev example we must be in the root of the project, in the package.json we have the `dev` command, that starts package compiler and dev example together.
```BASH
cd .. //if we be inside of /dev-example
npm run dev
```
And voila. The app are running in port 3001 because a config in my pc, if you have problems with this you can change it in package.json, `dev-example` command
### Running another example
In case you want to use another example to test what you are developing, please do the following:
1. In the `package.json` file of your example project, which can be located anywhere in your machine, link to the local version of `react-notion-render`:
```
"dependencies": {
"@9gustin/react-notion-render": "path/to-package"
}
```
This path can either be relative or absolute path.
2. Run `npm install` to install all the required packages for the example project, including the locally compiled version of `react-notion-render`.
3. Open a new terminal window and navigate to the `react-notion-render`. Run `npm start` to watch for changes you make to `react-notion-render` and build it on the go.
4. Go back to the terminal window with your example project and run `npm run dev` to test new changes of `react-notion-render` in the example.
### Project structure
| Directory | Description
| ---------- | ----------- |
`dev-example` | App maded with next.js, this app have the output of `src` as a package. You can test what are you developing here.
`src` | the package `@9gustin/react-notion-render`
`src/components` | React components
`src/components/common` | here are the "simple components", like all notion components and generic components(Link for example).
`src/components/core` | here are the logic components, the core of the package
`src/components/core/Render` | Render are the package exported component, the entry point of the package. It receives a list of blocks and render it.
`src/components/core/Text` | The text in notion are complex, this component contemplate text variants, like bold, italic. Also contemplate links.
`src/hoc` | Higher order components / in there we apply some logic rules.
`src/hoc/withContentValidation` | This HOC it's a filter before to pass the `Notion block` to the common components. almost every components are wrapped by this, and this objetive it's simplify props that the component would receive, applying package rules.
`src/hoc/withCustomComponent` | The package supports [custom components](#custom-components). This HOC make it possible. before to render text validate if the text are a custom component and render it.
`src/styles` | package styles. We just use plain css, the objective it's not apply much style, just the necessary. We use :global() to avoid compile problems with the className
`src/types` | Types of the package
`src/utils` | Common functions
`src/index.tsx` | All that the package exports outside
## License
MIT © [9gustin](https://github.com/9gustin)