How to create renderer plugin from scratch
This guide walks you through creating a custom JSX renderer plugin. We’ll build it step by step, starting with the basics.
Basic Structure
First, we need to create our renderer class that extends the base plugin and then we define the template for the renderer:
|
|
Let’s understand what’s happening:
- We extend
BaseRendererPlugin
to get core rendering capabilities - Our template defines the output structure with two variables:
imports
: For component importscontent
: For the actual content
- The template creates a React component that wraps our content
Adding config
To allow customization, we’ll introduce a configuration option in the plugin’s metadata. In this example, users can specify a custom name for the component.
|
|
Note that we’ve replaced NotionContent
with the {{{component}}}
variable (name it whatever you want). We’ll be dynamically substituting with the component name specified in the user’s configuration.
Adding Annotation Transformers
Annotation transformers handle inline text formatting. Each transformer converts Notion’s text formatting to JSX:
|
|
Tip
Read more about annotation transformers
Let’s add these to our renderer:
|
|
Adding Block Transformers
Let’s add more essential block transformers and integrate them into our renderer:
|
|
Tip
Read more about block transformers and their interaction with variables.
Now let’s update our renderer to use these transformers:
|
|
Adding Variable Resolvers
To handle our template variables (imports
, content
, and component
), we need to create resolvers. Each variable get assiged a default resolver which works fine for imports
and content
but for component
we needs a custom resolver since it has different use case.
|
|
Tip
Read more about variables and resolvers.
Let’s add these resolvers to our renderer:
|
|
Using the Renderer
Now that we have our JSX renderer complete, here’s how to use it:
import { NotionToMarkdown } from 'notion-to-md';
import { JSXRenderer } from './jsx-renderer';
const n2m = new NotionToMarkdown({ notionClient });
// Create instance of JSX renderer with custom config
const jsxRenderer = new JSXRenderer({
componentName: 'MyNotionContent'
});
// Use the renderer
n2m.setRenderer(jsxRenderer);
// Convert blocks to JSX
const jsx = await n2m.convert(blocks);
This will output JSX code that looks like:
export function MyNotionContent({ components = {} }) {
return (
<div className="notion-content">
<h1 className="notion-h1">Welcome to Notion</h1>
<p className="notion-paragraph">This is a paragraph with some <strong>bold</strong> text.</p>
<pre className="notion-code">
<code className="language-javascript">
console.log('Hello World');
</code>
</pre>
</div>
);
}
Next Steps
- Add more block transformers for other Notion block types
- Implement custom styling system
- Add support for interactive components
- Handle nested blocks (like toggle lists)
- Add proper TypeScript types for components props
Remember that this is a basic implementation. You can extend it further based on your specific needs by adding more transformers, improving the styling, or adding additional features.