PDF Export
It's possible to export BlockNote documents to PDF, completely client-side.
This feature is provided by the @blocknote/xl-pdf-exporter. xl- packages
are fully open source, but released under a copyleft license. A commercial
license for usage in closed source, proprietary products comes as part of the
Business subscription.
First, install the @blocknote/xl-pdf-exporter and @react-pdf/renderer packages:
npm install @blocknote/xl-pdf-exporter @react-pdf/rendererThen, create an instance of the PDFExporter class. This exposes the following methods:
import {
PDFExporter,
pdfDefaultSchemaMappings,
} from "@blocknote/xl-pdf-exporter";
import * as ReactPDF from "@react-pdf/renderer";
// Create the exporter
const exporter = new PDFExporter(editor.schema, pdfDefaultSchemaMappings);
// Convert the blocks to a react-pdf document
const pdfDocument = await exporter.toReactPDFDocument(editor.document);
// Use react-pdf to write to file:
await ReactPDF.render(pdfDocument, `filename.pdf`);See the full example with live PDF preview below:
Customizing the PDF
toReactPDFDocument takes an optional options parameter, which allows you to customize the header and footer of the PDF:
Example usage:
import { Text } from "@react-pdf/renderer";
const pdfDocument = await exporter.toReactPDFDocument(editor.document, {
header: <Text>Header</Text>,
footer: <Text>Footer</Text>,
});Custom mappings / custom schemas
The PDFExporter constructor takes a schema and mappings parameter.
A mapping defines how to convert a BlockNote schema element (a Block, Inline Content, or Style) to a React-PDF element.
If you're using a custom schema in your editor, or if you want to overwrite how default BlockNote elements are converted to PDF, you can pass your own mappings:
For example, use the following code in case your schema has an extraBlock type:
import { PDFExporter, pdfDefaultSchemaMappings } from "@blocknote/xl-pdf-exporter";
import { Text } from "@react-pdf/renderer";
new PDFExporter(schema, {
blockMapping: {
...pdfDefaultSchemaMappings.blockMapping,
myCustomBlock: (block, exporter) => {
return <Text>My custom block</Text>;
},
},
inlineContentMapping: pdfDefaultSchemaMappings.inlineContentMapping,
styleMapping: pdfDefaultSchemaMappings.styleMapping,
});Math & diagram blocks
The math and diagram blocks live in separate packages, and so do their PDF mappings. Spread them into the default mappings to export math blocks as vector formulas (via @react-pdf/math), inline math as images flowing with the text, and diagrams as embedded images:
import {
PDFExporter,
pdfDefaultSchemaMappings,
} from "@blocknote/xl-pdf-exporter";
import {
createInlineMathMapping,
mathBlockMapping,
} from "@blocknote/math-block/pdf-exporter";
import { createDiagramBlockMapping } from "@blocknote/diagram-block/pdf-exporter";
const exporter = new PDFExporter(editor.schema, {
...pdfDefaultSchemaMappings,
blockMapping: {
...pdfDefaultSchemaMappings.blockMapping,
math: mathBlockMapping,
diagram: createDiagramBlockMapping(),
},
inlineContentMapping: {
...pdfDefaultSchemaMappings.inlineContentMapping,
inlineMath: createInlineMathMapping(),
},
});Math blocks require the @react-pdf/math package. Invalid LaTeX or Mermaid sources render an error placeholder identifying the offending source, mirroring the editor. Note that the PDF exporter renders LaTeX with MathJax while the editor (and the DOCX/ODT exporters) use KaTeX — rare constructs supported by only one of the two may render differently.
Math blocks export fine server-side (they're vector output, no rasterization involved). Inline math and diagrams, however, are rasterized to images, which the built-in implementations can only do in the browser. When exporting server-side, plug in your own — without one, the export throws:
createInlineMathMapping({ rasterize })— aRasterizeSVGfunction, e.g. backed by@resvg/resvg-jsorsharp.createDiagramBlockMapping({ renderDiagram })— aRenderDiagramfunction, e.g. backed by@mermaid-js/mermaid-clior a Kroki server.
Exporter options
The PDFExporter constructor takes an optional options parameter.
While conversion happens on the client-side, the default setup uses two server based resources:
const defaultOptions = {
// emoji source, this is passed to the react-pdf library (https://react-pdf.org/fonts#registeremojisource)
// these are loaded from cloudflare + twemoji by default
emojiSource: {
format: "png",
url: "https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/",
},
// a function to resolve external resources in order to avoid CORS issues
// by default, this calls a BlockNote hosted server-side proxy to resolve files
resolveFileUrl: corsProxyResolveFileUrl,
// the strings rendered into the exported document (file link texts, error
// placeholders); pass a locale from @blocknote/core/locales (or your
// editor's dictionary) to export in another language
dictionary: locales.en,
// the colors to use in the PDF for things like highlighting, background colors and font colors.
colors: COLORS_DEFAULT, // defaults from @blocknote/core
};