react-pdf について
React-PDF で PDF 文書を生成するスキルです。Flexbox、グラフィック、カスタムフォントを使うレポートやフォームに対応し、レンダリング、プレビュー、トラブルシューティングの手順も扱います。
主な機能
- 01複数ページの PDF 文書作成
- 02Flexbox コンポーネントによるレイアウト構成
- 03画像、リンク、SVG グラフィックの埋め込み
- 04ローカルフォントと絵文字素材の登録
- 05レンダリング済み PDF ページのプレビュー
活用シーン
- 01レポート、請求書、履歴書の生成
- 02グリッド、カード、段組みを使った PDF の作成
- 03PDF へのチャート、アイコン、カスタムフォントの追加
- 04画像プレビューによるページレイアウトの確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trailofbits/ skills-curated --skill react-pdfインストール後、Claude Code で/react-pdfを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/example-template.tsxreferences/components.mdgoogle-fonts.txt詳細
React-PDF を使用した PDF の生成
使用する場合
- PDF ドキュメント(レポート、請求書、履歴書、フォーム、証明書)を生成する場合
- 複雑なレイアウト(複数列、グリッド、カード)が必要な PDF を作成する場合
- インライン SVG グラフィック、グラフ、アイコンを含む PDF を作成する場合
- カスタム Google Fonts や絵文字を使用したドキュメントを作成する場合
- 絶対座標を計算するよりも Flexbox レイアウトのほうが簡単な PDF 関連の作業全般
使用しない場合
- 既存の PDF からテキストを読み取る、または抽出する場合 — 代わりに
pdfplumberまたはpypdfを使用してください - 既存の PDF フォームに入力する場合 — Python の
pypdfまたはpdftkを使用してください - HTML を PDF に変換する場合 — 代わりに Playwright または WeasyPrint を使用してください
- レイアウトが不要な、単発のシンプルなテキスト PDF の場合 — Python スクリプトのほうが簡単なことがあります
重要な要件
- フォントは必ずローカルファイルにしてください - リモートフォントの URL(http/https)は動作しません。使用する前に、必ずフォントをダウンロードしてローカルファイルに保存してください。
- 非同期コードは IIFE で囲んでください - トップレベルの await はエラーの原因になります。必ず
(async () => { ... })()パターンを使用してください。 - カスタムフォントではハイフネーションを無効にしてください - カスタムフォントにはハイフネーション辞書がなく、クラッシュしたり、単語が不適切に分割されたりする可能性があります。カスタムフォントを登録した後、必ず
Font.registerHyphenationCallback((word) => [word]);を呼び出してください。
ファイル
{baseDir}/skills/react-pdf/references/google-fonts.txt- 人気のある約 65 種類の Google Fonts の TrueType URL を含むメタデータです。各 行は、タブ区切り形式のフォントバリアントです:font name、style、category、weight、url。{baseDir}/skills/react-pdf/references/components.md- コンポーネント API とサポートされている CSS プロパティの詳細なリファレンスです{baseDir}/skills/react-pdf/assets/example-template.tsx- 固定フッター、ページ番号、 および分割不可コンテンツを示す、最小限の動作例です。基本パターンを理解するために、作業を始める前にお読みください。注:ここにすべての API が示されているわけではありません。完全な API については、必ずドキュメントと{baseDir}/skills/react-pdf/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 は JSX を直接実行できません。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 />);
})();
スタイリング
方法は 3 つあります:StyleSheet.create()、インラインオブジェクト、または配列との組み合わせです。
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",
}
画像
ローカルファイルが最も確実です。ネットワークや CORS の問題により、リモート URL は失敗する場合があります。
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
{baseDir}/skills/react-pdf/references/google-fonts.txt を使ってフォントの URL を確認し、ローカルにダウンロードしてください。
# Find the font URL
grep "^Roboto" {baseDir}/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 ファイルを探してください。
絵文字
絵文字ソースを登録しないと、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}を使用します - 改ページをテストします。コンテンツの流れ方は予想と異なる場合があります
- 絶対位置指定よりも Flexbox を優先します
- すべてのページにヘッダー/フッターを表示するには
fixedプロパティを使用します - 要素の境界を可視化するには
debug={true}を使用します - レンダリングを try-catch ブロックで囲みます
よくある問題
テキストのオーバーフロー:<Text style={{ width: 200, maxLines: 3, textOverflow: "ellipsis" }}>...</Text>
フォントが見つからない:ローカルにダウンロードし、ローカルファイルパスで登録します。リモート URL は機能しません。
予期しない改ページ:コンテンツをまとめて表示するには wrap={false} を使用するか、<View break /> で強制的に改ページします。