react-pdf

Generate PDF documents using React-PDF library (@react-pdf/renderer). Use when creating PDFs,

INSTALLATION
npx skills add https://github.com/molefrog/skills --skill react-pdf
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

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 (async () => { ... })()

pattern.

  • 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

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.

Basic Example

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 tsx to execute them:

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:

// 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 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:

pdftoppm -png -r 200 document.pdf preview

# → preview-1.png, preview-2.png, ...

Option 2: PyMuPDF (Python) — fallback if pdftoppm is not available:

pip install pymupdf
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

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: StyleSheet.create(), inline objects, or mixed arrays.

const styles = StyleSheet.create({ container: { padding: 20 } });

<View style={styles.container} />

<View style={{ padding: 20 }} />

<View style={[styles.container, { marginTop: 10 }]} />

Supported Units

pt (default, 72 DPI), in, mm, cm, %, vw, vh

Common Style Properties

{

  // 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.

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

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:

npm install lucide-static
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

<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

<Text render={({ pageNumber, totalPages }) => `Page ${pageNumber} of ${totalPages}`} />

Fixed Headers/Footers

<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

<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 break

Custom Fonts

CRITICAL: All font sources MUST be local file paths. Remote URLs do not work.

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:

# 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.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.

npm install twemoji-emojis
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

// 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 StyleSheet.create() — define styles once and reuse
  • Compress images before embedding, use cache={true} for remote images
  • Test page breaks — content may flow differently than expected
  • Prefer flexbox over absolute positioning
  • Use fixed prop for headers/footers on every page
  • Use debug={true} to visualize element boundaries
  • 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 wrap={false} to keep content together, or <View break /> to

force breaks.

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card