react-pdf — Claude Code skill: generate PDFs from JSON specs
Renders PDF documents from JSON specs using @react-pdf/renderer. Use it when you need to build invoices, reports, or forms programmatically from structured data.
npx skills add vercel-labs/json-render --skill react-pdf -a claude-codeWhat react-pdf does
The skill turns a JSON spec into a PDF buffer, stream, or file — three render methods (renderToBuffer, renderToStream, renderToFile). Ships with a standard component catalog: Document, Page, Table, Heading, Text, Image, Link, List, Divider, Spacer, PageNumber. Each element is described in JSON with type, props, and children.
Requires installing @json-render/core and @json-render/react-pdf. You can extend the catalog with custom components: define a schema with Zod, register a React component, pass the registry to render. For state control there's StateStore, for server-side imports use @json-render/react-pdf/server without React in the bundle.
What it helps with
- generate an invoice with an item table and totals
- build a PDF report from dashboard data
- export a form submission to a printable document
- construct a document with custom components like badges
- pipe a PDF stream to an HTTP response without writing to disk
Example prompts for the agent
- Generate a PDF invoice from a JSON spec with a product table and total
- Create a PDF report: h1 heading, two text paragraphs, table with Item and Price columns
- Export the spec to `output.pdf` file using `renderToFile`
How to install react-pdf
1Skills CLI (Vercel)
npx skills add vercel-labs/json-render --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 vercel-labs/json-render --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 vercel-labs/json-render --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 vercel-labs/json-render react-pdf2Manually: put the files in place
.github/skills/react-pdf/SKILL.md1Skills CLI (Vercel)
npx skills add vercel-labs/json-render --skill react-pdf -a gemini-cli2Platform CLI
gemini skills install https://github.com/vercel-labs/json-render --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 vercel-labs/json-render --skill react-pdf -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
From the same set20
The whole set →Similar
Questions about react-pdf
How to install react-pdf in Claude Code?
Run npx skills add vercel-labs/json-render --skill react-pdf -a claude-code. The skill will appear in ~/.claude/skills/react-pdf/SKILL.md.
What does the react-pdf skill do?
Generates PDF documents from JSON specs using @react-pdf/renderer. Supports rendering to buffer, stream, or file, provides a standard component catalog, and allows adding custom components.
What components are available in react-pdf?
The standard catalog includes Document, Page, View, Row, Column, Heading, Text, Image, Link, Table, List, Divider, Spacer, PageNumber. You can register your own through defineCatalog and Zod schemas.
Source text
SKILL.md · Apache-2.0
---
name: react-pdf
description: React PDF renderer for json-render. Use when generating PDF documents from JSON specs, working with @json-render/react-pdf, or rendering specs to PDF buffers/streams/files.
---
# @json-render/react-pdf
React PDF renderer that generates PDF documents from JSON specs using `@react-pdf/renderer`.
## Installation
```bash
npm install @json-render/core @json-render/react-pdf
```
## Quick Start
```typescript
import { renderToBuffer } from "@json-render/react-pdf";
import type { Spec } from "@json-render/core";
const spec: Spec = {
root: "doc",
elements: {
doc: { type: "Document", props: { title: "Invoice" }, children: ["page"] },
page: {
type: "Page",
props: { size: "A4" },
children: ["heading", "table"],
},
heading: {
type: "Heading",
props: { text: "Invoice #1234", level: "h1" },
children: [],
},
table: {
type: "Table",
props: {
columns: [
{ header: "Item", width: "60%" },
{ header: "Price", width: "40%", align: "right" },
],
rows: [
["Widget A", "$10.00"],
["Widget B", "$25.00"],
],
},
children: [],
},
},
};
const buffer = await renderToBuffer(spec);
```
## Render APIs
```typescript
import { renderToBuffer, renderToStream, renderToFile } from "@json-render/react-pdf";
// In-memory buffer
const buffer = await renderToBuffer(spec);
// Readable stream (pipe to HTTP response)
const stream = await renderToStream(spec);
stream.pipe(res);
// Direct to file
await renderToFile(spec, "./output.pdf");
```
All render functions accept an optional second argument: `{ registry?, state?, handlers? }`.
## Standard Components
| Component | Description |
|-----------|-------------|
| `Document` | Top-level PDF wrapper (must be root) |
| `Page` | Page with size (A4, LETTER), orientation, margins |
| `View` | Generic container (padding, margin, background, border) |
| `Row`, `Column` | Flex layout with gap, align, justify |
| `Heading` | h1-h4 heading text |
| `Text` | Body text (fontSize, color, weight, alignment) |
| `Image` | Image from URL or base64 |
| `Link` | Hyperlink with text and href |
| `Table` | Data table with typed columns and rows |
| `List` | Ordered or unordered list |
| `Divider` | Horizontal line separator |
| `Spacer` | Empty vertical space |
| `PageNumber` | Current page number and total pages |
## Custom Catalog
```typescript
import { defineCatalog } from "@json-render/core";
import { schema, defineRegistry, renderToBuffer } from "@json-render/react-pdf";
import { standardComponentDefinitions } from "@json-render/react-pdf/catalog";
import { z } from "zod";
const catalog = defineCatalog(schema, {
components: {
...standardComponentDefinitions,
Badge: {
props: z.object({ label: z.string(), color: z.string().nullable() }),
slots: [],
description: "A colored badge label",
},
},
actions: {},
});
const { registry } = defineRegistry(catalog, {
components: {
Badge: ({ props }) => (
<View style={{ backgroundColor: props.color ?? "#e5e7eb", padding: 4 }}>
<Text>{props.label}</Text>
</View>
),
},
});
const buffer = await renderToBuffer(spec, { registry });
```
## External Store (Controlled Mode)
Pass a `StateStore` for full control over state:
Nested lists can set `repeat.statePath` to `{ "$item": "field" }` inside an enclosing repeat.
```typescript
import { createStateStore } from "@json-render/react-pdf";
const store = createStateStore({ invoice: { total: 100 } });
store.set("/invoice/total", 200);
```
## Server-Safe Import
Import schema and catalog without pulling in React:
```typescript
import { schema, standardComponentDefinitions } from "@json-render/react-pdf/server";
```
© vercel-labs · Apache-2.0 · vercel-labs/json-render