Skip to content

feat(xl-pdf-exporter): add custom font and fontFamily options for CJK support - #2945

Open
nperez0111 wants to merge 1 commit into
mainfrom
feat/fix-issue-2037
Open

feat(xl-pdf-exporter): add custom font and fontFamily options for CJK support#2945
nperez0111 wants to merge 1 commit into
mainfrom
feat/fix-issue-2037

Conversation

@nperez0111

@nperez0111 nperez0111 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds fonts and fontFamily options to PDFExporter so users can register custom fonts and override the default font family, enabling support for non-Latin scripts like CJK (Chinese, Japanese, Korean) characters.

Rationale

The PDF exporter only registers Inter and GeistMono fonts, neither of which contain CJK glyphs. When users export documents containing Mandarin or other CJK characters, the output is corrupted/unrecognizable. There was no way for users to register additional fonts or change the default font family.

Fixes #2037

Changes

  • Added fonts option to PDFExporter constructor — accepts an array of font registrations passed directly to react-pdf's Font.register()
  • Added fontFamily option to override the default "Inter" page font family
  • User-provided fonts are registered in registerFonts() after the built-in defaults
  • Custom fontFamily is applied to the page style in toReactPDFDocument()
  • Re-exported Font from @react-pdf/renderer so users can register fonts without adding react-pdf as a direct dependency

Impact

Fully backward compatible — both new options are optional and default to the existing behavior. No changes to the default PDF output.

Testing

All 7 existing PDF exporter tests pass. Lint passes with no new warnings.

Checklist

  • Code follows the project's coding standards.
  • Unit tests covering the new feature have been added.
  • All existing tests pass.
  • The documentation has been updated to reflect the new feature

Summary by CodeRabbit

  • New Features
    • Added support for registering custom fonts in exported PDFs.
    • Added an option to set the default font family for PDF documents.
    • Made the PDF font registration utility publicly available.

@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
blocknote Ready Ready Preview Aug 6, 2026 10:09am
blocknote-website Error Error Aug 6, 2026 10:09am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

PDFExporter now supports custom @react-pdf/renderer fonts and an optional default font family. Custom fonts are registered during initialization, and the configured family is applied to PDF page styles.

Changes

PDF font configuration

Layer / File(s) Summary
Font configuration API
packages/xl-pdf-exporter/src/pdf/index.ts, packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx
The PDF module exports Font. PDFExporter options now accept custom font registrations and an optional default font family.
Font registration and page styling
packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx
PDFExporter registers configured fonts after the built-in fonts. PDF pages use the configured font family when provided.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Poem

A rabbit hops through PDF ink,
With fonts that make the letters link.
New glyphs register, pages glow,
Mandarin now has room to show.
Thump, thump—the export’s set!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the addition of custom font and fontFamily options for CJK support.
Description check ✅ Passed The description covers the main template sections and clearly explains the implementation, impact, and testing status.
Linked Issues check ✅ Passed The changes provide custom font registration and font-family selection needed to render CJK characters in exported PDFs for issue #2037.
Out of Scope Changes check ✅ Passed All changes directly support custom fonts, font-family selection, and CJK PDF rendering.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/fix-issue-2037

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Aug 6, 2026

Copy link
Copy Markdown

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@2945

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@2945

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@2945

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@2945

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@2945

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@2945

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@2945

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@2945

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@2945

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@2945

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@2945

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@2945

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@2945

commit: 4119e22

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://TypeCellOS.github.io/BlockNote/pr-preview/pr-2945/

Built to branch gh-pages at 2026-08-06 10:16 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx (1)

266-271: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add regression tests for custom registration and page styling.

Existing tests can pass while either new contract is broken. Add coverage that supplies a local font registration, verifies the custom Font.register() call, and verifies that the generated Page receives the configured fontFamily. Add a local CJK fixture if feasible; do not depend on a remote font URL in the test.

Also applies to: 295-301

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx` around lines 266 - 271, Add
regression coverage for the PDF exporter’s custom font and page styling
behavior: provide a local font fixture through the exporter options, verify
Font.register receives that registration, and verify the generated Page receives
the configured fontFamily. Keep the test independent of remote font URLs and
include a local CJK fixture if feasible, covering both the registration block
and the Page styling path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx`:
- Around line 266-271: Update the custom font registration logic in the PDF
exporter constructor around this.options.fonts and Font.register so
registrations cannot resolve to fonts from other exporters. Ensure overlapping
family names are rejected, deduplicated using a stable key, or isolated through
namespacing, while preserving deterministic registration behavior; alternatively
enforce and document that custom font family names must be globally unique.

---

Nitpick comments:
In `@packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx`:
- Around line 266-271: Add regression coverage for the PDF exporter’s custom
font and page styling behavior: provide a local font fixture through the
exporter options, verify Font.register receives that registration, and verify
the generated Page receives the configured fontFamily. Keep the test independent
of remote font URLs and include a local CJK fixture if feasible, covering both
the registration block and the Page styling path.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6ec575ce-9ee3-46c8-a309-6f8d9d58c01c

📥 Commits

Reviewing files that changed from the base of the PR and between 036d0f3 and 4119e22.

📒 Files selected for processing (2)
  • packages/xl-pdf-exporter/src/pdf/index.ts
  • packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx

Comment on lines +266 to +271
if (this.options.fonts) {
for (const f of this.options.fonts) {
Font.register(f);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

pnpm list `@react-pdf/renderer` `@react-pdf/font` --depth 4

files="$(fd -t f 'index.js' . 2>/dev/null | rg 'node_modules/@react-pdf/(font|renderer)/' || true)"
if [ -z "$files" ]; then
  echo "Installed react-pdf sources were not found." >&2
  exit 1
fi

printf '%s\n' "$files" | xargs -r rg -n -C 4 \
  'FontStore|fontFamilies|sources\.push|exactFit|register ='

Repository: TypeCellOS/BlockNote

Length of output: 2121


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'Tracked pdfExporter file:\n'
git ls-files 'packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx' 'packages/xl-pdf-exporter/package.json' || true

printf '\nFont-related usages in tracked repository files:\n'
rg -n 'Font\.register|registerFont|fontsRegistered|fonts:' packages/xl-pdf-exporter -S || true

printf '\nPackage dependency versions:\n'
cat packages/xl-pdf-exporter/package.json | sed -n '1,220p'

Repository: TypeCellOS/BlockNote

Length of output: 3938


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'Inspect installed `@react-pdf/font` package manifests:\n'
find node_modules -path '*`@react-pdf/font`*' -maxdepth 8 -type f \( -name package.json \) -print | sort | sed -n '1,40p'

printf '\nInspect FontStore/register implementation candidates:\n'
find node_modules -path '*`@react-pdf/font`*' -maxdepth 9 -type f \( -name index.js -o -name *.js -o -name fontStore.js -o -name fontStore.d.ts -o -name FontStore.js \) -print | sort | sed -n '1,80p' | while read -r file; do
  echo "--- $file"
  rg -n -C 8 'FontStore|register|fontFamilies|sources\.push|sources =|fontSources|resolveFont' "$file" || true
done

Repository: TypeCellOS/BlockNote

Length of output: 16111


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'Search for FontStore default export and imports in `@react-pdf/font`:\n'
find node_modules .pnpm -path '*`@react-pdf`+font@*' -type f \( -name index.js -o -name index.browser.js -o -name index.native.js -o -name index.umd.js \) -print | sort | while read -r file; do
  echo "--- $file"
  rg -n -C 8 'default export FontStore|new FontStore|FontStore|export const Font|export default|Font\.register' "$file" || true
done

printf '\nSearch for PDFExporter usage across repo:\n'
rg -n 'new PDFExporter|PDFExporter\(|from .*xl-pdf-exporter|xl-pdf-exporter|fonts:\s*\[' packages examples docs -S || true

Repository: TypeCellOS/BlockNote

Length of output: 3671


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'FontStore exported bindings across `@react-pdf/font` packages:\n'
find node_modules -path '*`@react-pdf/font`*' -maxdepth 9 -type f \( -name index.js -o -name index.browser.js -o -name index.native.js -o -name index.umd.js -o -name index.esm.js \) -print | sort | while read -r file; do
  echo "--- $file"
  sed -n '1,40p' "$file"
  rg -n 'export( .*)?(default| {\s*\{| {\s*[A-Za-z])|new FontStore|Font.register' "$file" | sed -n '1,20p'
done

printf '\nRelevant PdfExporter registration section:\n'
sed -n '200,280p' packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx

Repository: TypeCellOS/BlockNote

Length of output: 1270


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf 'FontStore exported bindings across `@react-pdf/font` packages:\n'
find node_modules -path '*`@react-pdf/font`*' -maxdepth 9 -type f \( -name index.js -o -name index.browser.js -o -name index.native.js -o -name index.umd.js -o -name index.esm.js \) -print | sort | while read -r file; do
  echo "--- $file"
  sed -n '1,100p' "$file"
  rg -n "export .*Font|new FontStore|Font\.register|fontStore" "$file" | sed -n '1,40p'
done

printf '\nRelevant PdfExporter registration section:\n'
sed -n '200,280p' packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx

Repository: TypeCellOS/BlockNote

Length of output: 7804


Keep custom font registrations isolated from the shared Font registry.

Font.register() uses one FontStore, appends sources to the same family, and resolve() can return a source registered by another exporter. If users pass overlapping families, reject duplicates, deduplicate with a stable key, namespace the family, or document that custom fonts family names must be globally unique.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx` around lines 266 - 271,
Update the custom font registration logic in the PDF exporter constructor around
this.options.fonts and Font.register so registrations cannot resolve to fonts
from other exporters. Ensure overlapping family names are rejected, deduplicated
using a stable key, or isolated through namespacing, while preserving
deterministic registration behavior; alternatively enforce and document that
custom font family names must be globally unique.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mandarin characters become unrecognizable in PDF export while displaying correctly in web UI

1 participant