react-pdf · molefrog — Claude Code skill: what it does, how to install
Builds PDF documents using the @react-pdf/renderer library. Use it to render invoices, reports, and forms directly from TypeScript code.
npx skills add molefrog/skills --skill react-pdf -a claude-codeWhat react-pdf does
This skill teaches the agent how to build PDF files using @react-pdf/renderer and TypeScript. Document scripts run through tsx, so you do not need a tsconfig.json file. The skill bundle includes component references, Google Fonts metadata, and a starter template.
Remote font URLs over HTTP or HTTPS do not work in this setup. The build fails on web links, which means TrueType fonts must be saved locally before use. You also need to disable hyphenation for custom fonts with Font.registerHyphenationCallback((word) => [word]) to prevent rendering crashes.
All render calls must sit inside an (async () => { ... })() closure because top-level await causes errors. For quick visual review, the skill converts generated pages into PNG images using pdftoppm or Python's PyMuPDF.
What it helps with
- render PDF invoices and reports using React components
- run JSX document templates with
tsxwithout writing atsconfig.json - draw vector paths and gradients using
@react-pdf/rendererSVG tags - convert output PDF pages into PNG images for visual checks
Example prompts for the agent
- Create an invoice PDF template using @react-pdf/renderer
- Generate a multi-page PDF report with page numbers and fixed footers
- Write a react-pdf generation script and preview pages with pdftoppm
How to install react-pdf
1Skills CLI (Vercel)
npx skills add molefrog/skills --skill react-pdf -a claude-code2Manually: put the files in place
~/.claude/skills/react-pdf/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/react-pdf/
1Skills CLI (Vercel)
npx skills add molefrog/skills --skill react-pdf -a codex2Manually: put the files in place
.agents/skills/react-pdf/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add molefrog/skills --skill react-pdf -a cursor2Manually: put the files in place
.cursor/skills/react-pdf/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install molefrog/skills react-pdf2Manually: put the files in place
.github/skills/react-pdf/SKILL.md1Skills CLI (Vercel)
npx skills add molefrog/skills --skill react-pdf -a gemini-cli2Platform CLI
gemini skills install https://github.com/molefrog/skills --path skills/react-pdfManually: put the files in place
.devin/skills/react-pdf/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add molefrog/skills --skill react-pdf -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about react-pdf
How to install react-pdf in Claude Code?
Run npx skills add molefrog/skills --skill react-pdf -a claude-code. The skill file is placed in ~/.claude/skills/react-pdf/SKILL.md.
What does the react-pdf skill do?
It supplies guidelines, components, and templates to generate PDF files through @react-pdf/renderer.
Why must fonts be stored as local files?
Remote font URLs over HTTP and HTTPS fail during compilation. You must download TrueType font files to local storage before loading them into your document.
Source text
SKILL.md · MIT
---
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>
<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:
```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(<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:
```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(<MyDocument />, "./document.pdf");
})();
// To buffer
(async () => {
const buffer = await renderToBuffer(<MyDocument />);
})();
```
## Styling
Three methods: `StyleSheet.create()`, inline objects, or mixed arrays.
```tsx
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
```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-static
```
```tsx
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 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 "<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.
```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: `<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
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**: `<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.
© molefrog · MIT · molefrog/skills
Similar skills
Everything for Office documents →react-pdf by other authors comes first.