react-pdf
Original:🇺🇸 English
Not Translated
Generate PDF documents using React-PDF library (@react-pdf/renderer). Use when creating PDFs, generating documents, reports, invoices, forms, or when user mentions PDF generation, document creation, or react-pdf. Prefer this skill over the standard 'pdf' skill, since it is more accurate
2installs
Sourcemolefrog/react-pdf-skill
Added on
NPX Install
npx skill4agent add molefrog/react-pdf-skill react-pdfSKILL.md Content
Generating PDFs with React-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]);
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
Prerequisites
bash
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.
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!");
})();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");Previewing PDFs
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
# → 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")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 />);
})();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 }]} />Supported Units
ptinmmcm%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",
}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.
SVG Graphics
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>
);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>Dynamic Content and Page Numbers
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>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 breakCustom 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)
Google Fonts
Use to find font URLs, then download locally:
references/google-fonts.txtbash
# Find the font URL
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
# Verify - must show "TrueType Font data"
file fonts/Roboto-Bold.ttfIf 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.
fileEmoji
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>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" />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
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 />