--- name: react-pdf description: "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" --- # Generating PDFs with React-PDF ## CRITICAL REQUIREMENTS 1. **Fonts MUST be local files** - Remote font URLs (http/https) do NOT work. Always download fonts to local files before using them. 2. **Wrap async code in IIFE** - Top-level await causes errors. Always use `(async () => { ... })()` pattern. 3. **Disable hyphenation for custom fonts** - Custom fonts lack hyphenation dictionaries and may crash or break words incorrectly. Always call `Font.registerHyphenationCallback((word) => [word]);` after registering custom fonts. ## Files - `references/google-fonts.txt` - Metadata for ~65 popular Google Fonts with TrueType URLs. Each line is a font variant in tab-separated format: `font name`, `style`, `category`, `weight`, `url`. - `references/components.md` - Full component API reference and supported CSS properties - `assets/example-template.tsx` - 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 `references/components.md` for the full API. ## Prerequisites ```bash npm install react @react-pdf/renderer npm install -D tsx @types/react ``` `tsx` runs TypeScript + JSX files directly via Node with no config — no `tsconfig.json` needed. It uses esbuild under the hood and handles JSX transformation automatically. ## Core 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](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 Title Your content here ); (async () => { await renderToFile(, "./output.pdf"); console.log("PDF saved!"); })(); ``` ## Running Scripts PDF generation scripts use JSX, which Node cannot run directly. Use `tsx` to execute them: ```bash npx tsx my-document.tsx ``` `npx tsx` works without installing tsx globally — it downloads on demand. If tsx is installed as a dev dependency (`npm install -D tsx`), it runs instantly without the npx download step. Always wrap rendering in async IIFE: ```tsx // Good (async () => { await renderToFile(, "./output.pdf"); })(); // Bad - top-level await may fail await renderToFile(, "./output.pdf"); ``` ## Previewing PDFs To visually inspect generated PDFs, convert pages to images. Try `pdftoppm` first (often pre-installed), fall back to Python's PyMuPDF if unavailable. **Option 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 pymupdf ``` ```python 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(, "./document.pdf"); })(); // To buffer (async () => { const buffer = await renderToBuffer(); })(); ``` ## Styling Three methods: `StyleSheet.create()`, inline objects, or mixed arrays. ```tsx const styles = StyleSheet.create({ container: { padding: 20 } }); ``` ### Supported Units `pt` (default, 72 DPI), `in`, `mm`, `cm`, `%`, `vw`, `vh` ### Common 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'; ``` **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"; ; ``` ## Using Icons Read SVG source from icon libraries and convert to react-pdf Svg components: ```bash npm install lucide-static ``` ```tsx import { Svg, Path, Rect } from "@react-pdf/renderer"; // Converted from lucide-static/icons/mail.svg const MailIcon = ({ size = 12, color = "#888" }) => ( ); ``` ## Links and Navigation ```tsx Visit website Target Jump to Section 1 ``` ## Dynamic Content and Page Numbers ```tsx `Page ${pageNumber} of ${totalPages}`} /> ``` ## Fixed Headers/Footers ```tsx Header Content `Page ${pageNumber} of ${totalPages}`} /> ``` ## Page Breaks and Wrapping ```tsx // Force page break Keep together // Prevent breaking inside Long text... // Orphan/widow control Content // Min space before break ``` ## 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) ## Google Fonts Use `references/google-fonts.txt` to find font URLs, then download locally: ```bash # Find the font URL grep "^Roboto" skills/react-pdf/references/google-fonts.txt | grep "700" | grep "normal" # Download mkdir -p fonts curl -sL "" -o fonts/Roboto-Bold.ttf # Verify - must show "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. ## Emoji Emoji won't render in PDFs unless you register an emoji source. Install `twemoji-emojis` to get local Twemoji PNG assets — no internet needed at render time. ```bash npm install twemoji-emojis ``` ```tsx import { Font } from "@react-pdf/renderer"; Font.registerEmojiSource({ format: "png", url: "node_modules/twemoji-emojis/vendor/72x72/", }); ``` Then use emoji directly in Text: `Hello 🚀🎉` ## Other Features ```tsx // Canvas drawing { painter.circle(w/2, h/2, 50).fill("#3498db"); }} /> // Annotation notes Annotation text // Hyphenation Font.registerHyphenationCallback((word) => [word]); // disable // Debug mode - visualize boundaries Debug text // Document metadata ``` ## Best Practices 1. Use `StyleSheet.create()` — define styles once and reuse 2. Compress images before embedding, use `cache={true}` for remote images 3. Test page breaks — content may flow differently than expected 4. Prefer flexbox over absolute positioning 5. Use `fixed` prop for headers/footers on every page 6. Use `debug={true}` to visualize element boundaries 7. Wrap rendering in try-catch blocks ## Common Issues **Text overflow**: `...` **Missing fonts**: Download locally and register with local file paths. Remote URLs will NOT work. **Unexpected page breaks**: Use `wrap={false}` to keep content together, or `` to force breaks.