12k

@json-render/react-pdf

PDF document renderer. Turn JSON specs into PDFs using @react-pdf/renderer.

Install#

npm install @json-render/core @json-render/react-pdf

See the React PDF example for a full working example.

schema#

The PDF element schema for document specs. Use with defineCatalog from core.

import { defineCatalog } from '@json-render/core';
import { schema, standardComponentDefinitions } from '@json-render/react-pdf';

const catalog = defineCatalog(schema, {
  components: standardComponentDefinitions,
});

Render Functions#

Server-side functions for producing PDF output. All accept a spec and optional RenderOptions.

import { renderToBuffer, renderToStream, renderToFile } from '@json-render/react-pdf';

const buffer = await renderToBuffer(spec);

const stream = await renderToStream(spec);
stream.pipe(res);

await renderToFile(spec, './output.pdf');

RenderOptions#

interface RenderOptions {
  registry?: ComponentRegistry;
  includeStandard?: boolean;  // default: true
  state?: Record<string, unknown>;
}
OptionDescription
registryCustom component map (merged with standard components)
includeStandardInclude built-in standard components (default: true)
stateInitial state for $state / $cond dynamic prop resolution

defineRegistry#

Create a type-safe component registry from a catalog. Components receive { props, children, emit, bindings, loading }.

import { defineRegistry } from '@json-render/react-pdf';
import { View, Text } from '@react-pdf/renderer';

const { registry } = defineRegistry(catalog, {
  components: {
    Badge: ({ props }) => (
      <View style={{ backgroundColor: props.color ?? '#e5e7eb', padding: 4, borderRadius: 4 }}>
        <Text style={{ fontSize: 10 }}>{props.label}</Text>
      </View>
    ),
  },
});

const buffer = await renderToBuffer(spec, { registry });

createRenderer#

Create a standalone renderer component wired to state, actions, and validation.

import { createRenderer } from '@json-render/react-pdf';

const PDFRenderer = createRenderer(catalog, components);
interface CreateRendererProps {
  spec: Spec | null;
  store?: StateStore;
  state?: Record<string, unknown>;
  onAction?: (actionName: string, params?: Record<string, unknown>) => void;
  onStateChange?: (changes: Array<{ path: string; value: unknown }>) => void;
  loading?: boolean;
  fallback?: ComponentRenderer;
}

When store is provided, state and onStateChange are ignored (controlled mode).

Renderer#

The main component that renders a spec to @react-pdf/renderer elements.

interface RendererProps {
  spec: Spec | null;
  registry?: ComponentRegistry;
  includeStandard?: boolean;  // default: true
  loading?: boolean;
  fallback?: ComponentRenderer;
}

Standard Components#

Document Structure#

Document

Top-level PDF wrapper. Must be the root element. Children must be Page components.

{
  title: string | null;
  author: string | null;
  subject: string | null;
}

Page

A page in the document with configurable size, orientation, and margins.

{
  size: "A4" | "A3" | "A5" | "LETTER" | "LEGAL" | "TABLOID" | null;
  orientation: "portrait" | "landscape" | null;
  marginTop: number | null;
  marginBottom: number | null;
  marginLeft: number | null;
  marginRight: number | null;
  backgroundColor: string | null;
}

Layout#

View

Generic container with padding, margin, background, border, and flex alignment.

{
  padding: number | null;
  paddingTop: number | null;
  paddingBottom: number | null;
  paddingLeft: number | null;
  paddingRight: number | null;
  margin: number | null;
  backgroundColor: string | null;
  borderWidth: number | null;
  borderColor: string | null;
  borderRadius: number | null;
  flex: number | null;
  alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
}

Row

Horizontal flex layout with optional wrapping.

{
  gap: number | null;
  alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
  padding: number | null;
  flex: number | null;
  wrap: boolean | null;
}

Column

Vertical flex layout.

{
  gap: number | null;
  alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
  padding: number | null;
  flex: number | null;
}

Content#

Heading

h1-h4 heading text with configurable color and alignment.

{
  text: string;
  level: "h1" | "h2" | "h3" | "h4" | null;
  color: string | null;
  align: "left" | "center" | "right" | null;
}

Text

Body text with full styling control.

{
  text: string;
  fontSize: number | null;
  color: string | null;
  align: "left" | "center" | "right" | null;
  fontWeight: "normal" | "bold" | null;
  fontStyle: "normal" | "italic" | null;
  lineHeight: number | null;
}

Image

Image from a URL with optional dimensions and fit.

{
  src: string;
  width: number | null;
  height: number | null;
  objectFit: "contain" | "cover" | "fill" | "none" | null;
}

Link

Hyperlink with visible text.

{
  text: string;
  href: string;
  fontSize: number | null;
  color: string | null;
}

Data#

Table

Data table with typed columns and string rows. Supports header styling and striped rows.

{
  columns: { header: string; width?: string; align?: "left" | "center" | "right" }[];
  rows: string[][];
  headerBackgroundColor: string | null;
  headerTextColor: string | null;
  borderColor: string | null;
  fontSize: number | null;
  striped: boolean | null;
}

List

Ordered or unordered list.

{
  items: string[];
  ordered: boolean | null;
  fontSize: number | null;
  color: string | null;
  spacing: number | null;
}

Decorative#

Divider

Horizontal line separator.

{
  color: string | null;
  thickness: number | null;
  marginTop: number | null;
  marginBottom: number | null;
}

Spacer

Empty vertical space.

{
  height: number | null;
}

Page-Level#

PageNumber

Renders current page number and total pages. Format uses {pageNumber} and {totalPages} placeholders.

{
  format: string | null;    // default: "{pageNumber} / {totalPages}"
  fontSize: number | null;
  color: string | null;
  align: "left" | "center" | "right" | null;
}

External Store (Controlled Mode)#

Pass a StateStore to StateProvider, JSONUIProvider, or createRenderer for full control over state:

import { createStateStore, type StateStore } from "@json-render/react-pdf";

const store = createStateStore({ invoice: { total: 100 } });
store.set("/invoice/total", 200);

When store is provided, initialState / state and onStateChange are ignored.

Server-Safe Import#

Import schema and catalog definitions without pulling in React or @react-pdf/renderer:

import { schema, standardComponentDefinitions } from '@json-render/react-pdf/server';

Sub-path Exports#

ExportDescription
@json-render/react-pdfFull package: schema, renderer, components, render functions
@json-render/react-pdf/serverSchema and catalog definitions only (no React)
@json-render/react-pdf/catalogStandard component definitions and types
@json-render/react-pdf/renderServer-side render functions only

Types#

ExportDescription
ReactPdfSchemaSchema type for PDF specs
ReactPdfSpecSpec type for PDF documents
RenderOptionsOptions for render functions
ComponentContextTyped component render function context
ComponentFnComponent render function type
StandardComponentDefinitionsType of the standard component definitions object
StandardComponentProps<K>Inferred props type for a standard component by name