react-pdf について
TypeScript と JSX で React-PDF を使い、PDF を生成するためのスキルガイドです。ドキュメント部品、レイアウト、フォント、レンダリング、プレビューを扱い、安定した出力に必要な制約も説明します。
主な機能
- 01React-PDF コンポーネントで文書を構成
- 02再利用可能なスタイルとレイアウト
- 03ローカルフォントの登録
- 04PDF をファイルやバッファーに出力
- 05ページ番号と固定ヘッダーの追加
- 06ページ画像によるプレビュー
活用シーン
- 01JSX からページ付き文書を生成
- 02カスタムローカルフォントで PDF を作成
- 03改ページとレンダリング結果を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ molefrog/ skills --skill react-pdfインストール後、Claude Code で/react-pdfを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/example-template.tsxreferences/components.mdgoogle-fonts.txt詳細
React-PDF で PDF を生成する
重要な要件
- フォントは必ずローカルファイルにしてください — リモートフォントの URL(http/https)は動作しません。使用する前に、必ずフォントをローカルファイルにダウンロードしてください。
- 非同期コードは IIFE で囲んでください — トップレベルの await はエラーの原因になります。常に
(async () => { ... })()パターンを使用してください。 - カスタムフォントではハイフネーションを無効にしてください — カスタムフォントにはハイフネーション辞書がなく、クラッシュしたり、単語が誤って分割されたりする可能性があります。カスタムフォントを登録した後は、必ず
Font.registerHyphenationCallback((word) => [word]);を呼び出してください。
ファイル
references/google-fonts.txt— 約 65 種類の人気の Google Fonts のメタデータと TrueType URL。各行はタブ区切り形式のフォントバリアントです:font name、style、category、weight、url。references/components.md— コンポーネント API の完全なリファレンスと、サポートされている CSS プロパティassets/example-template.tsx— 固定フッター、ページ番号、分割不可のコンテンツを示す、最小構成の動作するサンプルです。基本的なパターンを理解するため、作業を始める前にお読みください。注:ここに示されている API は一部のみです。完全な API については、必ずドキュメントとreferences/components.mdを参照してください。
前提条件
npm install react @react-pdf/renderer
npm install -D tsx @types/react
tsx は Node 上で設定ファイルなしに TypeScript + JSX ファイルを直接実行するため、tsconfig.json は不要です。内部では esbuild を使用し、JSX の変換も自動で処理します。
コアコンポーネント
- Document:ルートコンポーネント(メタデータ、設定)
- Page:個々のページ(A4、Letter、またはカスタムサイズ)
- View:コンテナーコンポーネント(div に類似)
- Text:テキストコンテンツ。インラインスタイルを適用するためのネストに対応
- Image:画像の埋め込み(JPG、PNG、base64)
- Link:クリック可能なハイパーリンク(外部または内部)
- Note:注釈
- Canvas:pdfkit のメソッドを使った自由形式の描画
- Svg:ベクターグラフィックス(Circle、Rect、Path、Line、Polygon など)
- StyleSheet:再利用可能なスタイルの作成
コンポーネントの props と CSS プロパティの全容については、 references/components.md を参照してください。
基本的な例
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!");
})();
スクリプトの実行
PDF 生成スクリプトでは JSX を使用しますが、Node はそのままでは実行できません。tsx を使って実行してください:
npx tsx my-document.tsx
npx tsx は tsx をグローバルにインストールしなくても動作し、必要に応じてダウンロードします。tsx が開発依存関係としてインストールされている場合(npm install -D tsx)、npx によるダウンロードの手順が不要なため、すぐに実行できます。
レンダリングは必ず非同期 IIFE で囲んでください:
// Good
(async () => {
await renderToFile(<MyDocument />, "./output.pdf");
})();
// Bad - top-level await may fail
await renderToFile(<MyDocument />, "./output.pdf");
PDF のプレビュー
生成した PDF を目視で確認するには、ページを画像に変換します。まず pdftoppm を試してください(多くの場合、あらかじめインストールされています)。利用できない場合は、Python の PyMuPDF を使用してください。
オプション 1:pdftoppm(poppler-utils) — 多くの環境ではインストール不要のため、こちらを推奨します:
pdftoppm -png -r 200 document.pdf preview
# → preview-1.png, preview-2.png, ...
オプション 2:PyMuPDF(Python) — pdftoppm が利用できない場合の代替手段です:
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")
レンダリング方法
import { renderToFile, renderToBuffer } from "@react-pdf/renderer";
// To file
(async () => {
await renderToFile(<MyDocument />, "./document.pdf");
})();
// To buffer
(async () => {
const buffer = await renderToBuffer(<MyDocument />);
})();
スタイリング
StyleSheet.create()、インラインオブジェクト、または配列との組み合わせの 3 つの方法があります。
const styles = StyleSheet.create({ container: { padding: 20 } });
<View style={styles.container} />
<View style={{ padding: 20 }} />
<View style={[styles.container, { marginTop: 10 }]} />
サポートされている単位
pt(デフォルト、72 DPI)、in、mm、cm、%、vw、vh
よく使われるスタイルプロパティ
{
// 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",
}
画像
ローカルファイルが最も確実です。リモート URL はネットワークや CORS の問題により失敗する場合があります。
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 グラフィックス
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>;
アイコンの使用
アイコンライブラリの SVG ソースを読み取り、react-pdf の Svg コンポーネントに変換します:
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>
);
リンクとナビゲーション
<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>
動的コンテンツとページ番号
<Text render={({ pageNumber, totalPages }) => `Page ${pageNumber} of ${totalPages}`} />
固定ヘッダー/フッター
<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>
改ページと折り返し
<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
カスタムフォント
重要:フォントのソースはすべてローカルファイルのパスでなければなりません。 リモート URL は動作しません。
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]);
組み込みフォント: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
references/google-fonts.txt を使ってフォントの URL を確認し、ローカルにダウンロードします。
# 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
file に「HTML document」または「ASCII text」と表示される場合、ダウンロードに失敗しています。別の URL を試すか、GitHub でフォントの公式リポジトリを検索し、TTF ファイルを入手してください。
Emoji
絵文字ソースを登録しないと、絵文字は PDF に表示されません。twemoji-emojis をインストールすると、ローカルの Twemoji PNG アセットを入手できます。レンダリング時にインターネット接続は不要です。
npm install twemoji-emojis
import { Font } from "@react-pdf/renderer";
Font.registerEmojiSource({
format: "png",
url: "node_modules/twemoji-emojis/vendor/72x72/",
});
その後、Text 内で絵文字を直接使用できます:<Text>Hello 🚀🎉</Text>
その他の機能
// 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" />
ベストプラクティス
StyleSheet.create()を使用し、スタイルを一度定義して再利用します- 画像を埋め込む前に圧縮し、リモート画像には
cache={true}を使用します - 改ページをテストします。コンテンツの流れ方が想定と異なる場合があります
- 絶対位置指定よりもフレックスボックスを優先します
- すべてのページにヘッダー/フッターを表示するには
fixedプロパティを使用します - 要素の境界を可視化するには
debug={true}を使用します - レンダリングを try-catch ブロックで囲みます
よくある問題
テキストのはみ出し:<Text style={{ width: 200, maxLines: 3, textOverflow: "ellipsis" }}>...</Text>
フォントが見つからない:フォントをローカルにダウンロードし、ローカルのファイルパスを指定して登録します。リモート URL は機能しません。
予期しない改ページ:コンテンツをまとめて表示するには wrap={false} を使用するか、改ページを強制するには <View break /> を使用します。