Skip to content

tamimbinhakim/imprint-pdf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
imprint-pdf — author PDFs as React components, styled with real Tailwind, rendered without Chromium.

License: Apache-2.0 TypeScript Code style: Biome pnpm Conventional Commits Status: 1.0.0-alpha GitHub Repo stars Sponsor

A typesafe, edge-native, framework-agnostic PDF library for React. Real Tailwind. Real typography. No Chromium.

import { pdf, Document, Page } from '@imprint-pdf/react';

const response = await pdf(
  <Document>
    <Page size="A4" className="p-12 font-sans bg-white">
      <h1 className="text-3xl font-bold tracking-tight">Hello, PDF</h1>
      <p className="mt-4 text-base leading-relaxed text-pretty">
        Real Tailwind. Real React. Real typography. No browser.
      </p>
    </Page>
  </Document>,
);

That's it. pdf() returns a Response you can hand to any web framework. Pass { as: 'bytes' } for a Uint8Array, { as: 'stream' } for a ReadableStream. Everything else is config the library doesn't make you write.

Why

Generating a PDF in a JavaScript app shouldn't require launching a 200 MB browser. It shouldn't require learning a hand-rolled StyleSheet DSL. It shouldn't require pushing coordinates by hand. And it should run in the same runtime as the rest of your code — Node, Bun, Vercel Edge, Cloudflare Workers, the browser.

imprint-pdf gives you the actual Tailwind v4 Oxide compiler, the actual HarfBuzz shaping engine, the actual Knuth–Plass justification algorithm, and the actual Taffy layout engine (Block + Flexbox + CSS Grid). All Apache-2.0. All in one install.

Features

  • Real Tailwind classes. p-4 grid grid-cols-12 gap-6 text-pretty — the real compiler, not a translator, not a subset. Plugins, arbitrary values, OKLCH colors, and @theme design tokens all work. Supports Tailwind v3 and v4 — auto-detected from your project's installed version.
  • Real React. A custom reconciler. JSX components, refs, hooks. HTML elements (<div>, <h1>, <table>) compile to semantically tagged PDF nodes. Works on React 18 and 19 — both reconciler majors are bundled.
  • Real typography. HarfBuzz shaping (Arabic, Indic, Thai, CJK, kerning, ligatures, variable fonts), Knuth–Plass justification, Plass page breaking (widows / orphans / footnotes).
  • One API. pdf(<Doc />) returns a Response. pdf(<Doc />, { as: 'bytes' }) returns a Uint8Array. pdf(<Doc />, { as: 'stream' }) returns a ReadableStream. Same function everywhere — Node, Bun, the browser, edge.
  • Edge-native. Sub-100 ms cold on Cloudflare Workers and Vercel Edge.
  • CSS Grid. Taffy (Rust → WASM). Block + Flexbox + Grid in one layout pass.
  • Vector charts. Recharts, Visx, ECharts, Observable Plot SVG output flows through the vector pipeline — crisp at any zoom, no rasterized PNG.
  • AcroForms in JSX. <TextField>, <Checkbox>, <RadioGroup>, <Signature> declared as components. Real PDF form fields, not screenshots.
  • Print-grade output. PDF/X-4 + CMYK + ICC profiles + PDF/UA-1 tagged PDF + PKCS#7 signing + factur-X / ZUGFeRD, all as opt-in add-ons.

Documentation

Full documentation lives in docs/. For LLMs / AI agents, see llms.txt (index) and llms-full.txt (single-file context).

  • Overview — what imprint-pdf does and where it fits
  • Quick start — render your first PDF in five minutes
  • Philosophy — why no Chromium, why real Tailwind
  • Concepts — documents, pages, layout, the writer
  • Guides — components, Tailwind, fonts, charts, forms, accessibility
  • Frameworks — Next.js, Vite, Bun, Cloudflare
  • Cookbook — invoices, contracts, reports
  • Reference — every component, every CLI flag

Install

pnpm add @imprint-pdf/react @imprint-pdf/core tailwindcss
pnpm add -D @imprint-pdf/cli
npx imprint init

imprint init detects your framework (Next.js, Vite, generic Node), wires the right plugin into your config, scaffolds an example template + route, and prints the first command to run.

Render

// Next.js / Hono / Bun route — returns a Response with PDF headers
import { pdf } from '@imprint-pdf/next';
export const GET = () => pdf(<Invoice data={data} />);
// Cloudflare Worker — same `pdf()`, edge-friendly build
import { pdf } from '@imprint-pdf/react/standalone';
import wasm from '@imprint-pdf/react/imprint.wasm';

export default {
  fetch: () => pdf(<Invoice data={} />, { wasm }),
};
// Writing to disk — `{ as: 'bytes' }` gives back a Uint8Array
import { pdf } from '@imprint-pdf/react';
import { writeFileSync } from 'node:fs';

const bytes = await pdf(<Invoice data={data} />, { as: 'bytes' });
writeFileSync('./invoice.pdf', bytes);

How it works

Source code  →  React reconciler  →  PdfNode IR
                                          │
                                          ▼
                                  Tailwind resolver
                              (Oxide v4 or PostCSS v3)
                                          │
                                          ▼
                            Layout pass  (Taffy WASM)
                          + inline layout (Parley-lite)
                          + Knuth–Plass paragraph breaker
                          + Plass page breaker
                                          │
                                          ▼
                            Text & vector pipeline
                          (HarfBuzz, ICU4X, fontkit, resvg)
                                          │
                                          ▼
                            PDF writer  (pdf-lib v0 → imprint-pdf v1)
                                          │
                                          ▼
                            Response | Uint8Array | ReadableStream

For the full design, see ARCHITECTURE.md.

How it compares

Capability @react-pdf Satori pdfme Forme Chromium SaaS Typst imprint-pdf
Real Tailwind classes ❌ (DSL) subset
React / JSX components part.
Edge runtimes (CF Workers) part. part.
CSS Grid ✅ (Taffy)
HarfBuzz-grade shaping
Knuth–Plass justification Prince ≈
Variable fonts part.
Arabic / Indic / Thai / CJK weak weak weak part.
Vector charts
AcroForms in JSX n/a tmpl.
PDF/X-4 + CMYK part. DocRaptor part.
PDF/UA-1 tagged PDF DocRaptor part.
Sub-100 ms edge cold start n/a part.
Same code: client + edge + server part. n/a

Benchmarks

Measured with @imprint-pdf/bench on an Apple M-series laptop (Node 20, 30 runs, 5 warmup), rendering the same 1-page invoice through every JSX-driven library.

Library mean p95 p99 Output
@imprint-pdf/react 4.3 ms 5.2 ms 5.8 ms 6.2 KB
@react-pdf/renderer 13.7 ms 15.6 ms 16.8 ms 3.3 KB
Puppeteer (warm, browser reused) 50.6 ms 51.1 ms 51.1 ms 46.9 KB
Puppeteer (cold, launch per render) 473 ms 494 ms 494 ms 46.9 KB

3.15× faster than @react-pdf/renderer on the only fair head-to-head comparison (both consume JSX, both run a layout pass). ~12× faster than warm Chromium, ~110× faster than cold Chromium — the cold number is what serverless functions actually pay, plus a 200 MB binary download.

pnpm bench                    # runs competitors + complexity + pipeline + features
pnpm bench:chromium           # opt-in, downloads Chromium on first run
pnpm bench:all                # everything, including chromium

Imperative libraries (pdfkit, pdf-lib, jsPDF) and template-based ones (pdfme) are intentionally excluded — they're a different paradigm and the comparison would flatter imprint-pdf on ergonomics while making it look slow on µs-per-glyph.

Examples

pnpm --filter @imprint-pdf/example-next-app dev

Status

1.0.0-alpha. Architecture is settled (ARCHITECTURE.md); the API is close. Pin exact versions.

Phase Versions What it means
Alpha 1.0.0-alpha.x Anything can change in any release.
Beta 1.0.0-beta.x Public API frozen modulo bugs. Soak before GA.
1.0 1.0.0 First stable release. Semver from here on.
Post-1.0 1.x.y+ Backwards-compatible features and fixes.

See STABILITY.md for the full contract.

Sponsor

imprint-pdf is Apache-2.0 and self-funded. If your company ships PDFs through it — or you'd like to — sponsorship is what unlocks the next milestones on the roadmap, including the v1.x custom PDF writer that drops the pdf-lib runtime dependency for a smaller bundle and edge-friendlier output.

GitHub Sponsors → @tamimbinhakim

Backers and sponsors will be credited in releases and the repo README.

License

Apache-2.0 — every package. Engine, React layer, Tailwind compiler, CLI, integrations, and the compliance & print add-ons (PDF/X-4 + CMYK + ICC, PDF/UA-1 tagged PDF, PKCS#7 signing, factur-X / ZUGFeRD). No commercial seats, no time-bombed source. See LICENSING.md.

Contributing

pnpm install
pnpm dev         # turbo run dev across all packages
pnpm test        # vitest across the monorepo
pnpm typecheck   # composite tsc
pnpm lint        # biome check

See CONTRIBUTING.md and .github/RELEASING.md.

© Tamim Bin Hakim and contributors.

About

Author PDFs as React components, styled with real Tailwind CSS. Runs anywhere JavaScript runs — Node, Bun, Cloudflare Workers, Vercel Edge. No Chromium. Ever.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages