Skip to main content

Context & Hooks

import {
NotionRendererProvider,
useNotionRenderer,
useNotionBlock,
} from "@noxion/notion-renderer";

The renderer uses a React context to pass configuration (record map, URL mappers, component overrides, theme settings) to all descendant block components. You can access this context in your own custom block overrides.


NotionRendererProvider

The context provider. Used internally by <NotionRenderer /> — you don't need to use this directly unless you're building a custom renderer from scratch.

Props

interface NotionRendererProviderProps {
value: NotionRendererContextValue;
children: ReactNode;
}

Usage

import { NotionRendererProvider } from "@noxion/notion-renderer";

<NotionRendererProvider value={contextValue}>
{children}
</NotionRendererProvider>

useNotionRenderer()

Access the full renderer context from within any block component or custom override.

Signature

function useNotionRenderer(): NotionRendererContextValue

Returns

The full NotionRendererContextValue object. See Context value for the shape.

Usage

import { useNotionRenderer } from "@noxion/notion-renderer";

function MyCustomBlock({ block }: NotionBlockProps) {
const { recordMap, darkMode, mapImageUrl, components } = useNotionRenderer();

return (
<div className={darkMode ? "dark" : "light"}>
{/* custom rendering */}
</div>
);
}
note

Must be called inside a component rendered within <NotionRendererProvider>. Since <NotionRenderer /> wraps everything in the provider, any block component (including blockOverrides) can safely call this hook.


useNotionBlock(blockId)

Resolve a Notion block by ID from the recordMap. Handles the nested { role, value } wrapper that the unofficial Notion API sometimes returns.

Signature

function useNotionBlock(blockId: string): Block | undefined

Parameters

ParameterTypeDescription
blockIdstringThe Notion block ID to resolve

Returns

Block | undefined — the resolved Block object from notion-types, or undefined if not found in the record map.

Internal behavior

The unofficial Notion API sometimes wraps block values as:

{
"role": "reader",
"value": { ...actual block data... }
}

useNotionBlock() unwraps this automatically, returning the inner Block regardless of the wrapper format.

Usage

import { useNotionBlock } from "@noxion/notion-renderer";

function MyCustomBlock({ blockId }: { blockId: string }) {
const block = useNotionBlock(blockId);

if (!block) return null;
if (!block.alive) return null;

return <div>{block.type}</div>;
}

useRendererPlugins()

Access the array of renderer plugins from the context.

Signature

function useRendererPlugins(): RendererPlugin[]

Returns

RendererPlugin[] — the plugins array from the renderer context, or an empty array if no plugins are configured.

Usage

import { useRendererPlugins } from "@noxion/notion-renderer";

function MyCustomBlock({ block, blockId }: NotionBlockProps) {
const plugins = useRendererPlugins();
// Use plugins for custom block resolution logic
}

useResolvedBlockRenderer()

Resolve the component that should render a specific block, considering plugin overrides.

Signature

function useResolvedBlockRenderer(): (
block: Block,
blockId: string,
parent?: Block
) => BlockOverrideResult | null

Returns

A function that takes a block and returns the override result (component + props) if a plugin provides one, or null for default rendering.

Usage

import { useResolvedBlockRenderer } from "@noxion/notion-renderer";

function CustomBlockDispatch({ block, blockId }: { block: Block; blockId: string }) {
const resolveRenderer = useResolvedBlockRenderer();
const override = resolveRenderer(block, blockId);

if (override) {
const { component: Component, props } = override;
return <Component block={block} blockId={blockId} level={0} {...props} />;
}

return <DefaultBlock block={block} />;
}

Context value

NotionRendererContextValue

interface NotionRendererContextValue {
// The full Notion page data
recordMap: ExtendedRecordMap;

// Maps a Notion page ID to a URL path
// Default: (id) => `/${id}`
mapPageUrl: MapPageUrlFn;

// Maps an image URL (e.g. S3 → stable proxy)
// Default: (url) => url
mapImageUrl: MapImageUrlFn;

// Component overrides (Image, Link, PageLink, blockOverrides)
components: NotionComponents;

// Whether to render the full page with title header
fullPage: boolean;

// Current dark mode state
darkMode: boolean;

// Whether blur-up image previews are enabled
previewImages: boolean;

// Optional Shiki-backed code highlighter
highlightCode?: HighlightCodeFn;

// The resolved root page ID
rootPageId?: string;

// Fallback page icon (emoji or image URL)
defaultPageIcon?: string | null;

// Fallback cover image URL
defaultPageCover?: string | null;

// Fallback cover vertical position (0–1)
defaultPageCoverPosition?: number;
// Array of renderer plugins
plugins?: RendererPlugin[];

// Whether to show block action buttons
showBlockActions?: boolean | ((blockType: string) => boolean);

// Set of heading IDs already used (for duplicate dedup)
headingIds?: Set<string>;
}

Default context values

When accessed outside a provider, useNotionRenderer() returns a safe default:

{
recordMap: { block: {}, collection: {}, collection_view: {}, collection_query: {}, notion_user: {}, signed_urls: {} },
mapPageUrl: (id) => `/${id}`,
mapImageUrl: (url) => url,
components: {},
fullPage: true,
darkMode: false,
previewImages: false,
plugins: [],
headingIds: new Set(),
}

Type function signatures

// Maps a Notion page ID to a URL
type MapPageUrlFn = (pageId: string) => string;

// Maps an image source URL (transforms S3/Notion URLs to stable proxies)
type MapImageUrlFn = (url: string, block: Block) => string;

// Accepts raw code and a language identifier; returns HTML string
type HighlightCodeFn = (code: string, language: string) => string;

Building a custom renderer

You can compose NotionRendererProvider, NotionBlock, and NotionBlockList to build your own renderer:

"use client";
import {
NotionRendererProvider,
NotionBlock,
useNotionRenderer,
} from "@noxion/notion-renderer";
import type { NotionRendererContextValue, ExtendedRecordMap } from "@noxion/notion-renderer";

function MyCustomHeader() {
const { rootPageId, recordMap } = useNotionRenderer();
// read page title from recordMap...
return <h1 className="my-title">...</h1>;
}

export function MyRenderer({
recordMap,
rootPageId,
}: {
recordMap: ExtendedRecordMap;
rootPageId: string;
}) {
const contextValue: NotionRendererContextValue = {
recordMap,
mapPageUrl: (id) => `/posts/${id}`,
mapImageUrl: (url) => url,
components: {},
fullPage: false,
darkMode: false,
previewImages: false,
rootPageId,
};

return (
<NotionRendererProvider value={contextValue}>
<article>
<MyCustomHeader />
<NotionBlock blockId={rootPageId} level={0} />
</article>
</NotionRendererProvider>
);
}