Documentation

Creating PDFs

@jasy/pdf lets you describe a document as a tree of components, the way you would build a user interface, and writes the PDF byte stream itself. No headless browser, no Java. You compose a few primitives - Page, Column, Row, Box, Text - and the engine lays them out.

Install

pnpm add @jasy/pdf@alpha

To run a TypeScript file directly and get full type support, add tsx and the Node type definitions as dev dependencies:

pnpm add -D tsx @types/node

Your first PDF

Create a file, paste this in, and you have a one-page PDF. It works in any project, whether your package.json uses commonjs or module.

import { writeFileSync } from "node:fs";
import { Document, Page, Text, renderToBytes } from "@jasy/pdf";

async function build() {
  const doc = Document([
    Page({ size: "A4", margin: 56 }, [
      Text("Hello from jasy", { size: 28, bold: true, color: "#1450aa" }),
      Text("Declarative PDFs in pure TypeScript.", { size: 13, color: "gray" }),
    ]),
  ]);

  writeFileSync("hello.pdf", await renderToBytes(doc));
}

build();

Run it with tsx (or your own build step):

npx tsx hello.ts

Open hello.pdf and there it is. The shape never changes: a Document holds Pages, a Page holds your content, and renderToBytes gives you a Uint8Array you can write to a file or stream to a browser. Prefer a string? Use renderPdf instead.

A real document

Layouts come from a handful of primitives. Column stacks its children with a gap, Divider draws a line, and Box wraps content with a background, padding and rounded corners.

import { writeFileSync } from "node:fs";
import { Document, Page, Column, Box, Text, Divider, renderToBytes } from "@jasy/pdf";

async function build() {
  const doc = Document([
    Page({ size: "A4", margin: 56 }, [
      Column({ gap: 12 }, [
        Text("Project Report", { size: 30, bold: true, color: "#1450aa" }),
        Text("A second look at the layout primitives.", { size: 13, color: "gray" }),
        Divider({ color: "steelblue" }),
        Box({ bg: "#1450aa11", padding: 16, radius: 8 }, [
          Text("A box with a soft background, padding and rounded corners."),
        ]),
      ]),
    ]),
  ]);

  writeFileSync("report.pdf", await renderToBytes(doc));
}

build();

That is the whole idea. Everything else is more of the same: more primitives, more props.

Where to next

  • Layout - Column, Row, Box, Spacer and Expanded in depth.
  • Text - sizes, weight, color, alignment and inline styling.
  • Tables, Images and Fonts.
jasypdf

Declarative PDFs in pure TypeScript. ZUGFeRD & XRechnung compliant, with no headless browser and no Java.

Resources

© 2026 Florian Heuberger · MIT License

Built with Nuxt · self-hosted fonts · no trackers