jspdf-utils
v0.5.6
Published
Utility helpers for jsPDF's doc.html() renderer with automatic page breaking, table splitting, and RTL support
Maintainers
Readme
jsPDF Utils
Utilities for rendering HTML into paginated PDF output with jsPDF and
html2canvas-pro.
Installation
npm install jspdf-utilsjspdf and html2canvas-pro are peer dependencies and will be installed automatically.
Exported API
generatePDF(doc, source, opts)generateImagePDF(source, opts)generateImages(source, opts)previewImages(source, container, opts)PAGE_SIZESPAGE_MARGINS- Types:
PageOptions,PageOptionsInput,ImagePDFOptions,MarginContentInput,Border,TextBorder
Type import example:
import type { PageOptionsInput } from "jspdf-utils";Quick Start
1) HTML -> vector/text PDF (doc.html)
import jsPDF from "jspdf";
import { generatePDF } from "jspdf-utils";
const target = document.getElementById("print-section");
if (!target) throw new Error("Missing #print-section");
const doc = new jsPDF({ unit: "mm" });
// Optional for Arabic/RTL text:
// doc.addFont("/fonts/arial.ttf", "arial", "normal");
// doc.addFont("/fonts/arial-bold.ttf", "arial", "bold");
await generatePDF(doc, target, {
format: "a4",
margin: { top: 20, right: 20, bottom: 20, left: 20 },
forcedPageCount: 1,
});
doc.save("output.pdf");2) HTML -> image-based PDF (raster pages)
import { generateImagePDF } from "jspdf-utils";
const target = document.getElementById("print-section");
if (!target) throw new Error("Missing #print-section");
const imagePDF = await generateImagePDF(target, {
format: "a5",
imageFormat: "PNG",
forcedPageCount: 1,
});
imagePDF.save("output-image.pdf");3) Preview pages as images in a container
import { previewImages } from "jspdf-utils";
const target = document.getElementById("print-section");
const preview = document.getElementById("preview-container");
if (!target || !preview) throw new Error("Missing preview elements");
await previewImages(target, preview, {
format: "a5",
forcedPageCount: 1,
});Options
PageOptionsInput
unit?: string(default:"mm")format?: "a0" | "a1" | "a2" | "a3" | "a4" | "a5" | "a6" | "letter" | "legal" | "tabloid"(default:"a4")pageWidth?: number(default comes fromformat)pageHeight?: number(default comes fromformat)margin?: number | { top?: number; right?: number; bottom?: number; left?: number }
Important:
generatePDF,generateImagePDF,generateImages, andpreviewImagesuse page sizing from theiropts(format/pageWidth/pageHeight).- Do not rely on
new jsPDF({ format: ... })to control layout ingeneratePDF; passformatinoptsinstead.
ImagePDFOptions
imageFormat?: "JPEG" | "PNG"imageQuality?: numberscale?: numbermarginContent?: MarginContentInputborder?: BordertextBorder?: TextBorderforcedPageCount?: numberrepeatTableHeaders?: boolean(default:true)
forcedPageCount behavior:
- Forces output to the first
Npages only. generatePDF: trims extra pages afterdoc.htmlrendering.generateImagePDF: only rasterizes and writes firstNpages.generateImagesandpreviewImages: only returns/displays firstNpages.- Invalid values (
<= 0,NaN,Infinity) are ignored.
repeatTableHeaders behavior:
- Accepted by
generatePDF,generateImagePDF,generateImages, andpreviewImages. - When a table is split across pages, its header rows (all rows in
<thead>, or a leading all-<th>row) are repeated at the top of each page the table continues onto — at most once per page. - Set to
falseto render the header only once, where the table starts.
html2canvasOptions behavior:
- Forwarded to html2canvas by
generatePDF,generateImagePDF, andgenerateImages(scaleis always derived from the page layout and cannot be overridden). - html2canvas clones the whole document into its render iframe. Since 0.5.3
the library prunes that clone to
<head>plus the render element and its ancestors, so the rest of the page (a large app UI, other offscreen copies) is neither cloned nor waited on. A caller-suppliedignoreElementsis applied on top of that pruning. imageTimeoutdefaults to 60s (html2canvas' own default is 15s), so a document with hundreds of photos isn't cut short while the last ones decode.generatePDFhands html2canvas its own, uncapped imagecache. html2canvas-pro ≥ 2 caps its cache at 100 entries (LRU) and offers no option to raise it; a document with more images than that lost its FIRST images (evicted while parsing, before they were drawn). Pass your owncacheor aproxyto keep html2canvas' cache instead.
Image handling (generatePDF):
- Every
<img>larger than 2× its laid-out size is redrawn at 2× and re-encoded before rendering, so the PDF never embeds full-resolution originals. Since 0.5.3 the re-encode is JPEG (quality 0.9); an image whose pixels actually use transparency is kept as PNG so its alpha survives. - Images already at or below 2× and supplied as data-URLs are embedded as-is. Supplying print-sized JPEG data-URLs up front therefore skips the canvas pass entirely.
Margin Content and Borders
marginContent, border, and textBorder are independent, top-level page
options. Each has its own margin property that controls its distance from the
page edge, fully decoupled from the main margin (which only controls where
the HTML content is placed).
MarginContentInput
top,right,bottom,left— each accepts:HTMLElementorstring(static, rendered once and reused), or(page: number, totalPages: number) => HTMLElement | string(per-page)
margin?— distance in mm from the page edge to the content area (default: format default margin)
Border
Draws a vector rectangle around the page.
color?: string(default:"#000000")width?: number— line width in mm (default:0.3)margin?— distance in mm from the page edge to the border (default: page margin)
TextBorder
Draws repeated text along all four page edges.
text: string— the text to repeatcolor?: string(default:"#000000")fontSize?: number— in mm (default:2.5)fontFamily?: string(default:"Arial, sans-serif")fontWeight?: string(default:"normal")gap?: number— gap between repetitions in mm (default:fontSize * 0.5)margin?— distance in mm from the page edge to the text border (default: page margin)
Rendering order
- Margin content, borders, and text borders are rendered beneath page content.
- Main document content stays visually above them.
Development
npm install
npm run devOpen http://localhost:5173.
License
MIT
Mixed-direction text
generatePDF automatically preserves Arabic/English bracket and parenthesis
context in selectable vector text. It resolves punctuation using the inherited
CSS direction and the Unicode Bidirectional Algorithm before the HTML renderer
splits text into words. The original element and its direction are unchanged;
image-based exports continue using the browser's text rendering.
The PDF text hook is scoped to the HTML render and removed on success or failure,
so subsequent direct doc.text() calls retain jsPDF's normal behavior. Consumers
do not need to preprocess text or install their own bidi event hooks. Arabic
fonts must still be registered as described above.
Regression tests
With Node.js 22.18+ (native TypeScript stripping), run npm test and
npm run build. Tests cover Arabic/English mixed names, brackets, numeric text,
canvas-direction fallback, repeated renders, and hook cleanup.
