mcpField
R
react-pdf

react-pdf

github.com/trailofbitsドキュメント52385 回インストール15 週間前に更新
リポジトリ

react-pdf について

React-PDF で PDF 文書を生成するスキルです。Flexbox、グラフィック、カスタムフォントを使うレポートやフォームに対応し、レンダリング、プレビュー、トラブルシューティングの手順も扱います。

主な機能

  1. 01複数ページの PDF 文書作成
  2. 02Flexbox コンポーネントによるレイアウト構成
  3. 03画像、リンク、SVG グラフィックの埋め込み
  4. 04ローカルフォントと絵文字素材の登録
  5. 05レンダリング済み PDF ページのプレビュー

活用シーン

  1. 01レポート、請求書、履歴書の生成
  2. 02グリッド、カード、段組みを使った PDF の作成
  3. 03PDF へのチャート、アイコン、カスタムフォントの追加
  4. 04画像プレビューによるページレイアウトの確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trailofbits/skills-curated --skill react-pdf

インストール後、Claude Code で/react-pdfを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
example-template.tsx
references/
components.md
google-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 スクリプトのほうが簡単なことがあります

重要な要件

  1. フォントは必ずローカルファイルにしてください - リモートフォントの URL(http/https)は動作しません。使用する前に、必ずフォントをダウンロードしてローカルファイルに保存してください。
  2. 非同期コードは IIFE で囲んでください - トップレベルの await はエラーの原因になります。必ず (async () => { ... })() パターンを使用してください。
  3. カスタムフォントではハイフネーションを無効にしてください - カスタムフォントにはハイフネーション辞書がなく、クラッシュしたり、単語が不適切に分割されたりする可能性があります。カスタムフォントを登録した後、必ず 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" />

ベストプラクティス

  1. StyleSheet.create() を使用してスタイルを一度定義し、再利用します
  2. 画像を埋め込む前に圧縮し、リモート画像には cache={true} を使用します
  3. 改ページをテストします。コンテンツの流れ方は予想と異なる場合があります
  4. 絶対位置指定よりも Flexbox を優先します
  5. すべてのページにヘッダー/フッターを表示するには fixed プロパティを使用します
  6. 要素の境界を可視化するには debug={true} を使用します
  7. レンダリングを try-catch ブロックで囲みます

よくある問題

テキストのオーバーフロー:<Text style={{ width: 200, maxLines: 3, textOverflow: "ellipsis" }}>...</Text>

フォントが見つからない:ローカルにダウンロードし、ローカルファイルパスで登録します。リモート URL は機能しません。

予期しない改ページ:コンテンツをまとめて表示するには wrap={false} を使用するか、<View break /> で強制的に改ページします。

コメント