Renderer API Reference
Rendering Pipeline
The rendering pipeline transforms a cell’s raw source string into rendered
output (HTML string or virtual DOM nodes). It is designed as a chain of composable
stages so plugins can hook in at any point.
graph TD
S(source string) --> PRE[Pre-process]
PRE -->|plugins transform| P[Parse]
P -->|markdown-it| AST[AST Transforms]
AST -->|plugins modify tokens| R[Render]
R -->|tokens to HTML| POST[Post-process]
POST -->|sanitize/highlight| O(rendered output)
style S fill:transparent,stroke-dasharray: 5 5
style O fill:transparent,stroke-dasharray: 5 5mermaid and expose it as globalThis.mermaid.Pipeline Stages
1. Pre-process
Plugins register preprocess(source, cell) hooks.
Use cases: expand shortcodes, strip front-matter, inject variables.
2. Parse
Default parser: markdown-it in CommonMark mode with HTML, linkify, and typographer enabled.
3. AST Transforms
Use cases: LaTeX ($...$ → KaTeX), Mermaid (fenced blocks → SVG placeholders),
table enhancements, embed mount points.
4. Render
Multiple renderers per cell type — first non-null result wins.
5. Post-process
Use cases: sanitization (DOMPurify), syntax highlighting (Shiki/Prism), link rewriting, image lazy loading.
// Parser interface
interface MarkdownParser {
parse(source: string): Token[];
render(tokens: Token[]): string;
use(plugin: MarkdownParserPlugin): void;
}
// AST Transform
type ASTTransformer = (tokens: Token[], cell: Cell) => Token[];
// Cell Renderer
interface CellRenderer {
id: string;
cellTypes: CellType[];
renderToHTML?(tokens: Token[], cell: Cell): string;
renderToVDOM?(tokens: Token[], cell: Cell): unknown;
priority?: number;
}
// Post-processor
type PostProcessor = (html: string, cell: Cell) => string;// RenderPipeline class
class RenderPipeline {
constructor(parser?: MarkdownParser);
addPreprocessor(id: string, fn: (s: string, c: Cell) => string, priority?: number): void;
addASTTransformer(id: string, fn: ASTTransformer, priority?: number): void;
addRenderer(renderer: CellRenderer): void;
addPostprocessor(id: string, fn: PostProcessor, priority?: number): void;
remove(id: string): void;
render(cell: Cell): RenderedCell;
renderAll(notebook: Notebook): RenderedCell[];
}
interface RenderedCell {
cellId: string;
html: string;
renderTime: number; // ms
cached: boolean;
}Caching Strategy
Content-addressed LRU cache (default: 200 entries):
- Cache key =
hash(cell.type + cell.source + relevantMetadata)using FNV-1a - Cell source change → invalidate that cell only
- Plugin registered/unregistered → clear entire cache
- Theme changed → clear entire cache
interface RenderCache {
get(key: string): string | null;
set(key: string, html: string): void;
has(key: string): boolean;
invalidate(key: string): void;
clear(): void;
size: number;
maxSize: number;
}// Incremental Rendering — for large notebooks (100+ cells)
interface IncrementalRenderer {
markDirty(cellId: string): void;
setViewport(startIndex: number, endIndex: number): void;
flush(): RenderedCell[];
getCachedRender(cellId: string): string | null;
}
// 1. Dirty tracking — cell:updated marks only that cell dirty
// 2. Viewport rendering — only visible cells render immediately
// 3. Background rendering — off-screen cells use requestIdleCallbackMarkdown-it Plugins
| Plugin | Purpose |
|---|---|
markdown-it-footnote |
Footnote syntax [^1] |
markdown-it-task-lists |
Checkbox lists - [x] |
markdown-it-anchor |
Heading anchors for TOC |
markdown-it-toc |
Table of contents generation |
markdown-it-attrs |
Custom attributes {.class #id} |
markdown-it-container |
Custom containers :::name |
markdown-it-sub |
Subscript ~sub~ |
markdown-it-sup |
Superscript ^sup^ |
markdown-it-mark |
Highlighted text ==mark== |
All optional and loaded only if the user opts in (tree-shakeable).
Sanitization
Rendered HTML passes through DOMPurify with a permissive scientific config.
Sanitization can be disabled per-cell via metadata.trusted = true for embed
cells that need full HTML access.
// Syntax Highlighting interface
interface SyntaxHighlighter {
highlight(code: string, language: string): string | Promise<string>;
languages(): string[];
loadLanguage(lang: string): Promise<void>;
}
// Default: Shiki (TextMate grammars, same as VS Code)
// Alternative: lighter Prism.js adapter also available