Appearance
Browser Usage
The package works with browser-friendly binary values. You can generate a PDF, wrap it in a Blob, and preview or download it.
ts
import { createDocument } from "@criston/zeropdf";
const doc = createDocument();
const page = doc.addPage();
page.text("Preview me", {
x: 56,
y: 760,
fontSize: 16
});
const blob = doc.toBlob();
const url = URL.createObjectURL(blob);
iframe.src = url;Streaming to a Response
Use WebStreamSink with a TransformStream to stream a PDF straight to the browser without buffering the whole document:
ts
import { WebStreamSink } from "@criston/zeropdf";
const { readable, writable } = new TransformStream<Uint8Array>();
const sink = new WebStreamSink(writable);
void doc.writeTo(sink).then(() => sink.close());
const response = new Response(readable, {
headers: { "Content-Type": "application/pdf" }
});BufferSink also works in the browser when you just need the bytes.
Browser limitations
The core engine — generation, parsing, editing, fonts, images, tables, templates, annotations, and tagged PDF — runs in the browser with no Node dependencies. Two areas are Node-only:
- Disk-backed output.
TempFileSink,NodeStreamSink, andwriteToFilerely onnode:fsand are not available in the browser. UsetoBlob(),toArrayBuffer(),toUint8Array(),BufferSink, orWebStreamSinkinstead. - AES encryption. AES-encrypting a document requires Node's
node:crypto; in the browser it throws"AES PDF encryption requires Node.js crypto support in this build."Generate unencrypted PDFs client-side and encrypt server-side if you need protection. (Secure random bytes fall back to the Web Crypto API where available.)
The Node-only sinks load node:fs through a lazy dynamic import(), so bundlers building for the browser will not pull them into the core path.
Playground
The repo includes a browser playground in examples/website: write template code on the left and see the rendered PDF on the right, all in-browser.
sh
npm run example:webOpen http://localhost:4173/, edit the code, and press Run (or ⌘/Ctrl+Enter). Every zeropdf export is in scope; your code just needs to build a document and return it.