react-pdf
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGenerating PDFs with React-PDF
使用React-PDF生成PDF
CRITICAL REQUIREMENTS
关键要求
- Fonts MUST be local files - Remote font URLs (http/https) do NOT work. Always download fonts to local files before using them.
- Wrap async code in IIFE - Top-level await causes errors. Always use pattern.
(async () => { ... })() - Disable hyphenation for custom fonts - Custom fonts lack hyphenation dictionaries and may
crash or break words incorrectly. Always call
after registering custom fonts.
Font.registerHyphenationCallback((word) => [word]);
- 字体必须是本地文件 - 远程字体URL(http/https)无法使用。使用前务必将字体下载到本地文件。
- 将异步代码包裹在IIFE中 - 顶层await会导致错误。务必使用模式。
(async () => { ... })() - 为自定义字体禁用断字功能 - 自定义字体缺少断字词典,可能会崩溃或错误拆分单词。注册自定义字体后务必调用。
Font.registerHyphenationCallback((word) => [word]);
Files
文件
- - Metadata for ~65 popular Google Fonts with TrueType URLs. Each line is a font variant in tab-separated format:
references/google-fonts.txt,font name,style,category,weight.url - - Full component API reference and supported CSS properties
references/components.md - - Minimal working example demonstrating fixed footers, page numbers, and unbreakable content. Read this before starting to understand the basic patterns. Note: not all APIs are shown here — always refer to the docs and
assets/example-template.tsxfor the full API.references/components.md
- - 约65种热门Google Fonts的元数据,包含TrueType URL。每行是一个字体变体,采用制表符分隔格式:
references/google-fonts.txt、字体名称、样式、类别、字重。URL - - 完整的组件API参考和支持的CSS属性
references/components.md - - 展示固定页脚、页码和不可拆分内容的最简可用示例。开始前请阅读此示例以了解基本模式。注意:此处未展示所有API — 如需完整API,请始终参考文档和
assets/example-template.tsx。references/components.md
Prerequisites
前置依赖
bash
npm install react @react-pdf/renderer
npm install -D tsx @types/reacttsxtsconfig.jsonbash
npm install react @react-pdf/renderer
npm install -D tsx @types/reacttsxtsconfig.jsonCore Components
核心组件
- Document: Root component (metadata, settings)
- Page: Individual pages (A4, Letter, or custom dimensions)
- View: Container component (similar to div)
- Text: Text content, supports nesting for inline styling
- Image: Embed images (JPG, PNG, base64)
- Link: Clickable hyperlinks (external or internal)
- Note: Annotation notes
- Canvas: Freeform drawing with pdfkit methods
- Svg: Vector graphics (Circle, Rect, Path, Line, Polygon, etc.)
- StyleSheet: Create reusable styles
For full component props and CSS properties, see
references/components.md.
- Document:根组件(元数据、设置)
- Page:单个页面(A4、Letter或自定义尺寸)
- View:容器组件(类似div)
- Text:文本内容,支持嵌套以实现内联样式
- Image:嵌入图片(JPG、PNG、base64)
- Link:可点击的超链接(外部或内部)
- Note:注释笔记
- Canvas:使用pdfkit方法进行自由绘制
- Svg:矢量图形(Circle、Rect、Path、Line、Polygon等)
- StyleSheet:创建可复用样式
如需完整的组件属性和CSS属性,请查看references/components.md。
Basic Example
基础示例
tsx
import React from "react";
import { Document, Page, Text, View, StyleSheet, renderToFile } from "@react-pdf/renderer";
const styles = StyleSheet.create({
page: { flexDirection: "column", backgroundColor: "#ffffff", padding: 40 },
title: { fontSize: 24, marginBottom: 20, fontWeight: "bold" },
text: { fontSize: 12, lineHeight: 1.5 },
});
const MyDocument = () => (
<Document>
<Page size="A4" style={styles.page}>
<View style={{ margin: 10, padding: 20 }}>
<Text style={styles.title}>Document Title</Text>
<Text style={styles.text}>Your content here</Text>
</View>
</Page>
</Document>
);
(async () => {
await renderToFile(<MyDocument />, "./output.pdf");
console.log("PDF saved!");
})();tsx
import React from "react";
import { Document, Page, Text, View, StyleSheet, renderToFile } from "@react-pdf/renderer";
const styles = StyleSheet.create({
page: { flexDirection: "column", backgroundColor: "#ffffff", padding: 40 },
title: { fontSize: 24, marginBottom: 20, fontWeight: "bold" },
text: { fontSize: 12, lineHeight: 1.5 },
});
const MyDocument = () => (
<Document>
<Page size="A4" style={styles.page}>
<View style={{ margin: 10, padding: 20 }}>
<Text style={styles.title}>Document Title</Text>
<Text style={styles.text}>Your content here</Text>
</View>
</Page>
</Document>
);
(async () => {
await renderToFile(<MyDocument />, "./output.pdf");
console.log("PDF saved!");
})();Running Scripts
运行脚本
PDF generation scripts use JSX, which Node cannot run directly. Use to execute them:
tsxbash
npx tsx my-document.tsxnpx tsxnpm install -D tsxAlways wrap rendering in async IIFE:
tsx
// Good
(async () => {
await renderToFile(<MyDocument />, "./output.pdf");
})();
// Bad - top-level await may fail
await renderToFile(<MyDocument />, "./output.pdf");PDF生成脚本使用JSX,Node无法直接运行。使用执行脚本:
tsxbash
npx tsx my-document.tsxnpx tsxnpm install -D tsx务必将渲染代码包裹在异步IIFE中:
tsx
// 正确写法
(async () => {
await renderToFile(<MyDocument />, "./output.pdf");
})();
// 错误写法 - 顶层await可能失败
await renderToFile(<MyDocument />, "./output.pdf");Previewing PDFs
预览PDF
To visually inspect generated PDFs, convert pages to images. Try first (often
pre-installed), fall back to Python's PyMuPDF if unavailable.
pdftoppmOption 1: pdftoppm (poppler-utils) — preferred, no install needed in many environments:
bash
pdftoppm -png -r 200 document.pdf preview如需可视化检查生成的PDF,可将页面转换为图片。优先尝试(通常已预装),若不可用则 fallback 到Python的PyMuPDF。
pdftoppm选项1:pdftoppm(poppler-utils) — 首选,许多环境中无需安装:
bash
pdftoppm -png -r 200 document.pdf preview→ preview-1.png, preview-2.png, ...
→ preview-1.png, preview-2.png, ...
**Option 2: PyMuPDF (Python)** — fallback if pdftoppm is not available:
```bash
pip install pymupdfpython
import fitz
doc = fitz.open("document.pdf")
for i, page in enumerate(doc):
pix = page.get_pixmap(dpi=200)
pix.save(f"page-{i+1}.png")
**选项2:PyMuPDF(Python)** — 若pdftoppm不可用则使用此备选方案:
```bash
pip install pymupdfpython
import fitz
doc = fitz.open("document.pdf")
for i, page in enumerate(doc):
pix = page.get_pixmap(dpi=200)
pix.save(f"page-{i+1}.png")Rendering Methods
渲染方法
tsx
import { renderToFile, renderToBuffer } from "@react-pdf/renderer";
// To file
(async () => {
await renderToFile(<MyDocument />, "./document.pdf");
})();
// To buffer
(async () => {
const buffer = await renderToBuffer(<MyDocument />);
})();tsx
import { renderToFile, renderToBuffer } from "@react-pdf/renderer";
// 渲染到文件
(async () => {
await renderToFile(<MyDocument />, "./document.pdf");
})();
// 渲染到缓冲区
(async () => {
const buffer = await renderToBuffer(<MyDocument />);
})();Styling
样式设置
Three methods: , inline objects, or mixed arrays.
StyleSheet.create()tsx
const styles = StyleSheet.create({ container: { padding: 20 } });
<View style={styles.container} />
<View style={{ padding: 20 }} />
<View style={[styles.container, { marginTop: 10 }]} />三种方式:、内联对象或混合数组。
StyleSheet.create()tsx
const styles = StyleSheet.create({ container: { padding: 20 } });
<View style={styles.container} />
<View style={{ padding: 20 }} />
<View style={[styles.container, { marginTop: 10 }]} />Supported Units
支持的单位
ptinmmcm%vwvhptinmmcm%vwvhCommon Style Properties
常见样式属性
tsx
{
// Flexbox
flexDirection: "row", justifyContent: "space-between", alignItems: "center",
flexWrap: "wrap", gap: 10,
// Box model
margin: 10, padding: 20, width: "100%", height: 200,
// Borders
borderWidth: 1, borderColor: "#333", borderRadius: 5, borderStyle: "solid",
// Colors
backgroundColor: "#f0f0f0", color: "#000", opacity: 0.8,
// Typography
fontSize: 12, fontWeight: "bold", fontFamily: "Helvetica", fontStyle: "italic",
lineHeight: 1.5, textAlign: "center", textDecoration: "underline",
textTransform: "uppercase", letterSpacing: 1,
// Position
position: "absolute", top: 0, left: 0, right: 0, bottom: 0, zIndex: 10,
// Transforms
transform: "rotate(45deg)", transformOrigin: "center",
}tsx
{
// Flexbox
flexDirection: "row", justifyContent: "space-between", alignItems: "center",
flexWrap: "wrap", gap: 10,
// 盒模型
margin: 10, padding: 20, width: "100%", height: 200,
// 边框
borderWidth: 1, borderColor: "#333", borderRadius: 5, borderStyle: "solid",
// 颜色
backgroundColor: "#f0f0f0", color: "#000", opacity: 0.8,
// 排版
fontSize: 12, fontWeight: "bold", fontFamily: "Helvetica", fontStyle: "italic",
lineHeight: 1.5, textAlign: "center", textDecoration: "underline",
textTransform: "uppercase", letterSpacing: 1,
// 定位
position: "absolute", top: 0, left: 0, right: 0, bottom: 0, zIndex: 10,
// 变换
transform: "rotate(45deg)", transformOrigin: "center",
}Images
图片
Local files are most reliable. Remote URLs may fail due to network/CORS issues.
tsx
import { Image } from '@react-pdf/renderer';
<Image src="./images/photo.jpg" style={{ width: 200, height: 150 }} />
<Image src={{ data: buffer, format: 'png' }} />SVG files cannot be used as Image sources. Read the SVG source and recreate using react-pdf Svg
components.
本地文件最可靠。远程URL可能因网络/CORS问题失败。
tsx
import { Image } from '@react-pdf/renderer';
<Image src="./images/photo.jpg" style={{ width: 200, height: 150 }} />
<Image src={{ data: buffer, format: 'png' }} />SVG文件不能作为Image组件的源。请读取SVG源码并使用react-pdf的Svg组件重新创建。
SVG Graphics
SVG图形
tsx
import { Svg, Circle, Rect, Path, Line, G, Defs, LinearGradient, Stop } from "@react-pdf/renderer";
<Svg width="200" height="200" viewBox="0 0 200 200">
<Defs>
<LinearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<Stop offset="0%" stopColor="#3498db" />
<Stop offset="100%" stopColor="#9b59b6" />
</LinearGradient>
</Defs>
<Circle cx="100" cy="100" r="50" fill="url(#grad1)" />
<Rect x="10" y="10" width="50" height="50" fill="#e74c3c" />
<Path d="M10,50 Q50,10 90,50" stroke="#2ecc71" strokeWidth="2" fill="none" />
</Svg>;tsx
import { Svg, Circle, Rect, Path, Line, G, Defs, LinearGradient, Stop } from "@react-pdf/renderer";
<Svg width="200" height="200" viewBox="0 0 200 200">
<Defs>
<LinearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<Stop offset="0%" stopColor="#3498db" />
<Stop offset="100%" stopColor="#9b59b6" />
</LinearGradient>
</Defs>
<Circle cx="100" cy="100" r="50" fill="url(#grad1)" />
<Rect x="10" y="10" width="50" height="50" fill="#e74c3c" />
<Path d="M10,50 Q50,10 90,50" stroke="#2ecc71" strokeWidth="2" fill="none" />
</Svg>;Using Icons
使用图标
Read SVG source from icon libraries and convert to react-pdf Svg components:
bash
npm install lucide-statictsx
import { Svg, Path, Rect } from "@react-pdf/renderer";
// Converted from lucide-static/icons/mail.svg
const MailIcon = ({ size = 12, color = "#888" }) => (
<Svg width={size} height={size} viewBox="0 0 24 24">
<Path d="m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7" stroke={color} strokeWidth={2} fill="none" />
<Rect x="2" y="4" width="20" height="16" rx="2" stroke={color} strokeWidth={2} fill="none" />
</Svg>
);从图标库读取SVG源码并转换为react-pdf的Svg组件:
bash
npm install lucide-statictsx
import { Svg, Path, Rect } from "@react-pdf/renderer";
// 从lucide-static/icons/mail.svg转换而来
const MailIcon = ({ size = 12, color = "#888" }) => (
<Svg width={size} height={size} viewBox="0 0 24 24">
<Path d="m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7" stroke={color} strokeWidth={2} fill="none" />
<Rect x="2" y="4" width="20" height="16" rx="2" stroke={color} strokeWidth={2} fill="none" />
</Svg>
);Links and Navigation
链接与导航
tsx
<Link src="https://example.com"><Text>Visit website</Text></Link>
<View id="section-1"><Text>Target</Text></View>
<Link src="#section-1"><Text>Jump to Section 1</Text></Link>tsx
<Link src="https://example.com"><Text>Visit website</Text></Link>
<View id="section-1"><Text>Target</Text></View>
<Link src="#section-1"><Text>Jump to Section 1</Text></Link>Dynamic Content and Page Numbers
动态内容与页码
tsx
<Text render={({ pageNumber, totalPages }) => `Page ${pageNumber} of ${totalPages}`} />tsx
<Text render={({ pageNumber, totalPages }) => `Page ${pageNumber} of ${totalPages}`} />Fixed Headers/Footers
固定页眉/页脚
tsx
<Page size="A4">
<View fixed style={{ position: "absolute", top: 20, left: 30, right: 30 }}>
<Text>Header</Text>
</View>
<View style={{ marginTop: 60, marginBottom: 60 }}>
<Text>Content</Text>
</View>
<Text
fixed
style={{ position: "absolute", bottom: 20, left: 30, right: 30, textAlign: "center" }}
render={({ pageNumber, totalPages }) => `Page ${pageNumber} of ${totalPages}`}
/>
</Page>tsx
<Page size="A4">
<View fixed style={{ position: "absolute", top: 20, left: 30, right: 30 }}>
<Text>Header</Text>
</View>
<View style={{ marginTop: 60, marginBottom: 60 }}>
<Text>Content</Text>
</View>
<Text
fixed
style={{ position: "absolute", bottom: 20, left: 30, right: 30, textAlign: "center" }}
render={({ pageNumber, totalPages }) => `Page ${pageNumber} of ${totalPages}`}
/>
</Page>Page Breaks and Wrapping
分页与内容包裹
tsx
<View break /> // Force page break
<View wrap={false}><Text>Keep together</Text></View> // Prevent breaking inside
<Text orphans={2} widows={2}>Long text...</Text> // Orphan/widow control
<View minPresenceAhead={100}><Text>Content</Text></View> // Min space before breaktsx
<View break /> // 强制分页
<View wrap={false}><Text>Keep together</Text></View> // 禁止内部拆分
<Text orphans={2} widows={2}>Long text...</Text> // 孤行/ widow 控制
<View minPresenceAhead={100}><Text>Content</Text></View> // 分页前最小预留空间Custom Fonts
自定义字体
CRITICAL: All font sources MUST be local file paths. Remote URLs do not work.
tsx
import { Font } from "@react-pdf/renderer";
Font.register({
family: "Roboto",
fonts: [
{ src: "./fonts/Roboto-Regular.ttf", fontWeight: "normal" },
{ src: "./fonts/Roboto-Bold.ttf", fontWeight: "bold" },
{ src: "./fonts/Roboto-Italic.ttf", fontStyle: "italic" },
],
});
// Always disable hyphenation when using custom fonts
Font.registerHyphenationCallback((word) => [word]);Built-in fonts: Courier, Helvetica, Times-Roman (each with Bold, Italic/Oblique variants)
Font weight values: thin (100), ultralight (200), light (300), normal (400), medium (500),
semibold (600), bold (700), ultrabold (800), heavy (900)
关键提示:所有字体源必须是本地文件路径。远程URL无法使用。
tsx
import { Font } from "@react-pdf/renderer";
Font.register({
family: "Roboto",
fonts: [
{ src: "./fonts/Roboto-Regular.ttf", fontWeight: "normal" },
{ src: "./fonts/Roboto-Bold.ttf", fontWeight: "bold" },
{ src: "./fonts/Roboto-Italic.ttf", fontStyle: "italic" },
],
});
// 使用自定义字体时务必禁用断字功能
Font.registerHyphenationCallback((word) => [word]);内置字体:Courier、Helvetica、Times-Roman(每种都有Bold、Italic/Oblique变体)
字体字重值:thin(100)、ultralight(200)、light(300)、normal(400)、medium(500)、semibold(600)、bold(700)、ultrabold(800)、heavy(900)
Google Fonts
Google Fonts
Use to find font URLs, then download locally:
references/google-fonts.txtbash
undefined使用查找字体URL,然后下载到本地:
references/google-fonts.txtbash
undefinedFind the font URL
查找字体URL
grep "^Roboto" skills/react-pdf/references/google-fonts.txt | grep "700" | grep "normal"
grep "^Roboto" skills/react-pdf/references/google-fonts.txt | grep "700" | grep "normal"
Download
下载
mkdir -p fonts
curl -sL "<url-from-grep>" -o fonts/Roboto-Bold.ttf
mkdir -p fonts
curl -sL "<url-from-grep>" -o fonts/Roboto-Bold.ttf
Verify - must show "TrueType Font data"
验证 - 必须显示"TrueType Font data"
file fonts/Roboto-Bold.ttf
If `file` shows "HTML document" or "ASCII text", the download failed. Try a different URL or search
GitHub for the font's official repo with TTF files.file fonts/Roboto-Bold.ttf
如果`file`命令显示“HTML document”或“ASCII text”,则下载失败。请尝试其他URL或在GitHub上搜索该字体的官方仓库以获取TTF文件。Emoji
表情符号
Emoji won't render in PDFs unless you register an emoji source. Install to get
local Twemoji PNG assets — no internet needed at render time.
twemoji-emojisbash
npm install twemoji-emojistsx
import { Font } from "@react-pdf/renderer";
Font.registerEmojiSource({
format: "png",
url: "node_modules/twemoji-emojis/vendor/72x72/",
});Then use emoji directly in Text:
<Text>Hello 🚀🎉</Text>除非注册表情符号源,否则表情符号无法在PDF中渲染。安装以获取本地Twemoji PNG资源 — 渲染时无需联网。
twemoji-emojisbash
npm install twemoji-emojistsx
import { Font } from "@react-pdf/renderer";
Font.registerEmojiSource({
format: "png",
url: "node_modules/twemoji-emojis/vendor/72x72/",
});然后可在Text组件中直接使用表情符号:
<Text>Hello 🚀🎉</Text>Other Features
其他功能
tsx
// Canvas drawing
<Canvas style={{ width: 200, height: 200 }}
paint={(painter, w, h) => { painter.circle(w/2, h/2, 50).fill("#3498db"); }} />
// Annotation notes
<Note style={{ color: "yellow" }}>Annotation text</Note>
// Hyphenation
Font.registerHyphenationCallback((word) => [word]); // disable
// Debug mode - visualize boundaries
<View debug><Text debug>Debug text</Text></View>
// Document metadata
<Document title="My Doc" author="Author" subject="Report" language="en-US" pdfVersion="1.5" />tsx
// Canvas绘制
<Canvas style={{ width: 200, height: 200 }}
paint={(painter, w, h) => { painter.circle(w/2, h/2, 50).fill("#3498db"); }} />
// 注释笔记
<Note style={{ color: "yellow" }}>Annotation text</Note>
// 断字功能
Font.registerHyphenationCallback((word) => [word]); // 禁用
// 调试模式 - 可视化边界
<View debug><Text debug>Debug text</Text></View>
// 文档元数据
<Document title="My Doc" author="Author" subject="Report" language="en-US" pdfVersion="1.5" />Best Practices
最佳实践
- Use — define styles once and reuse
StyleSheet.create() - Compress images before embedding, use for remote images
cache={true} - Test page breaks — content may flow differently than expected
- Prefer flexbox over absolute positioning
- Use prop for headers/footers on every page
fixed - Use to visualize element boundaries
debug={true} - Wrap rendering in try-catch blocks
- 使用— 定义一次样式并复用
StyleSheet.create() - 嵌入前压缩图片,对远程图片使用
cache={true} - 测试分页 — 内容的流动可能与预期不同
- 优先使用flexbox而非绝对定位
- 对每页的页眉/页脚使用属性
fixed - 使用可视化元素边界
debug={true} - 将渲染代码包裹在try-catch块中
Common Issues
常见问题
Text overflow:
<Text style={{ width: 200, maxLines: 3, textOverflow: "ellipsis" }}>...</Text>Missing fonts: Download locally and register with local file paths. Remote URLs will NOT work.
Unexpected page breaks: Use to keep content together, or to
force breaks.
wrap={false}<View break />文本溢出:
<Text style={{ width: 200, maxLines: 3, textOverflow: "ellipsis" }}>...</Text>字体缺失:下载到本地并使用本地文件路径注册。远程URL绝对无法使用。
意外分页:使用保持内容连续,或使用强制分页。
wrap={false}<View break />