# vue-pdf-export > `vue-pdf-export` is a vue + TypeScript browser-side HTML-to-PDF package with two rendering modes: high-fidelity Canvas rendering and selectable/searchable vector-text rendering. The project is maintained by Saurabh Choudhary. ## Primary resources - [Live playground](https://vue-pdf-export-playground.vercel.app/) - [npm package](https://www.npmjs.com/package/vue-pdf-export) - [Author portfolio](https://saurabhzaiswal.vercel.app/) - [Feedback / feature requests](https://vue-pdf-export.canny.io/) - [Funding](https://buymeacoffee.com/saurabhzaiswal) - [Documentation Link](https://vue-pdf-export-docs.vercel.app) The source repository is maintained privately. ## Package capabilities ### Core PDF workflow - Browser-side HTML-to-PDF generation - vue component API - Vue composable API - TypeScript declarations - PDF `Blob` output - PDF preview modal - PDF download - Programmatic print - Blob URL cleanup - Safe filename normalization - Shared public API across both render modes ### Rendering modes #### Canvas mode `renderMode="canvas"` - Default package mode for backwards compatibility - Uses `html2pdf.js` + `html2canvas` + `jsPDF` - Best choice when browser/CSS visual fidelity is the priority - Body content is rasterized and is therefore not normally selectable/searchable - Paginated documents with `.html2pdf__page-break` markers use incremental page-by-page Canvas rendering - Canvas documents without page-break markers retain the legacy whole-document html2pdf.js worker Incremental Canvas rendering: - renders one logical PDF page at a time - keeps raster captures page-bounded - removes temporary page DOM after capture - releases canvas backing stores after insertion - reports page-aware progress - yields to the browser between expensive steps - supports cooperative cancellation before subsequent work begins #### Selectable-text mode `renderMode="text"` - Emits real PDF text/vector operations for supported content - Selectable text - Searchable text - Copyable text - Selectable header/footer text - Selectable footer page numbers - Clickable PDF hyperlinks - Images - Backgrounds - Borders - Basic border radius - Text color, weight, italic, decoration, alignment, and spacing - Multi-page output - Manual page breaks - Password protection - PDF permissions - Metadata - Compression - Headers - Footers - Watermarks Selectable-text mode prioritizes real PDF text over pixel-perfect support for every browser CSS feature. ## Pagination - Manual pagination - Automatic height-based pagination - Page-break protection - Custom page-break avoidance selectors - Automatic pagination reset - Manual page breaks remain preserved when automatic pagination is reset - Automatic pagination accounts for selective header spacing Manual page-break marker: ```html
``` Recommended CSS: ```css .html2pdf__page-break { display: block; height: 0; clear: both; } ``` Do not add `break-before` or `page-break-before` to this helper while legacy html2pdf page-break behavior is active because duplicate or blank pages can result. Default page-break protection selectors include: ```text .pdf-keep-together .pdf-no-break img ``` ## Headers - Optional PDF headers - Plain-text header content - Trusted HTML header content with `headerHtml` - Non-empty `headerHtml` takes precedence over `headerText` - Optional header logo via `headerLogoEnabled` - Header images from URL or data URL - Configurable header logo width and height - Aspect-ratio-safe logo rendering - Header background and text colors - Header page targeting - Page-aware header spacing Header targeting supports: ```text all first last except-first number[] ``` Selective header targeting reserves header spacing only on pages that receive the header. Explicit user margins in `htmlToPdfOptions.margin` remain independent. `headerHtml` is trusted developer-controlled HTML and must not contain unsanitized user input. ## Footers - Optional PDF footers - HTML footer mode - Text footer mode - Plain-text footer content - Trusted HTML footer content with `footerHtml` - Non-empty `footerHtml` takes precedence over `footerText` in HTML mode - Optional footer logo via `footerLogoEnabled` - Footer images from URL or data URL - Configurable footer logo width and height - Aspect-ratio-safe logo rendering - Footer background and text colors - Footer page template with `{n}` and `{total}` - Legacy footer compatibility through `useFooterComponent` - Selectable footer text/page numbers in selectable-text mode Footer page numbering uses templates such as: ```text Page {n} of {total} ``` There is no separate dedicated page-numbering API. Footers currently use all-page behavior and do not have independent page targeting. `footerHtml` is trusted developer-controlled HTML and must not contain unsanitized user input. ## Footer performance optimization Static HTML footer content is rasterized once and reused across PDF pages. Dynamic page numbering remains separate and is drawn as jsPDF text. Recorded benchmark fixtures showed: - HTML footer without logo: `7.82 s -> 1.43 s` (~81.7% less time) - HTML footer with logo: `11.81 s -> 1.29 s` (~89.1% less time) - footer-heavy PDF size: `~46.7 MB -> ~1.0 MB` (~97.9% smaller) - footer no-logo peak heap: `102.6 MB -> 26.5 MB` (~74.2% lower) These values belong to the project benchmark fixtures and are not universal package-wide performance guarantees. ## Watermarks - Text watermarks - Image watermarks - Background watermarks - Foreground watermarks - Single watermark mode - Repeated/tiled watermark mode - Opacity - Rotation - Positioning - Spacing - Per-page watermark targeting Watermark page targeting supports: ```text all first last except-first number[] ``` Header targeting and watermark targeting are independent. ## Security - Optional PDF password protection - User/open password - Owner password - Password construction from multiple password parts - Configurable PDF permissions - Direct security props can override raw jsPDF encryption settings - Explicit `security.enabled: false` removes inherited raw encryption Supported permission values: ```ts type PdfPermission = | 'print' | 'modify' | 'copy' | 'annot-forms' ``` `passwordParts` are combined into one final user/open password. They do not create multiple independent valid passwords. PDF permission enforcement is viewer-dependent. ## Encrypted Canvas memory behavior Large encrypted Canvas/raster PDFs can retain substantially more memory than equivalent unencrypted Canvas PDFs in Chromium. The same encrypted-raster retention pattern was reproduced with raw jsPDF outside the Vue component lifecycle. For that reason this behavior is treated as an upstream/dependency concern rather than described as a confirmed Vue memory leak. Upstream tracking: https://github.com/parallax/jsPDF/issues/4017 Practical guidance: - avoid unnecessarily high Canvas scale values - resize oversized images before generation - generate one very large PDF at a time - prefer selectable-text mode when it meets visual requirements - test encrypted long documents on representative target devices - consider splitting exceptionally large documents when browser memory is constrained ## Metadata and compression Metadata supports: - title - author - subject - keywords - creator The direct `metadata` prop takes priority over compatible raw metadata configuration. The package also supports optional jsPDF stream compression. The direct `compress` prop takes priority over compatible raw `htmlToPdfOptions.jsPDF.compress`. Compression does not reduce html2canvas resolution or JPEG quality. ## Links When PDF links are enabled, real `` elements can become clickable PDF annotations. Selectable-text mode keeps link text selectable. ## Progress and loading - Built-in loader - Custom loader slot - Numeric progress updates - Rich progress-stage updates - Page-aware `currentPage` / `totalPages` progress Progress stages: ```text idle pagination images preparing rendering watermark header footer metadata serializing complete error ``` Example `PdfProgressState`: ```ts { stage: 'rendering', progress: 57, currentPage: 21, totalPages: 100 } ``` Progress values represent generation work, not byte-level network transfer progress. ## Cancellation The component exposes: ```ts cancelGeneration(): void ``` Example: ```ts pdfRef.value?.cancelGeneration() ``` Cancellation is cooperative. Incremental Canvas rendering checks cancellation around page capture, encoding, insertion, and browser-yield checkpoints. Selectable-text rendering checks cancellation during DOM walking, image materialization, pagination, and page rendering. Already-running synchronous browser/jsPDF operations cannot be interrupted in the middle; cancellation takes effect at the next safe checkpoint. Cancellation is treated as an expected abort flow rather than a normal package error. Regression tests verify cancellation cleanup and successful generation recovery afterward. ## Repeated-image optimization Selectable-text rendering uses a per-generation cache for repeated real `` sources when these match: - image source/currentSrc - target raster width - target raster height - image format - JPEG quality The cache is cleared after each generation. Canvas elements are not cached because their pixels may change even if their dimensions stay the same. In the image-heavy selectable regression fixture: - 10 pages = 40 image elements - 25 pages = 100 image elements - 50 pages = 200 image elements - encoding work remained bounded to <= 4 calls in the regression test This represents avoided repeated encoding work for that fixture, not a universal end-to-end speedup percentage. ## Large-document behavior The current automated benchmark and regression suite verifies documents through 100-page fixtures. This is the current verified regression range, not a hard package page-count limit. Large-document engineering includes: - 10 / 25 / 50 / 100-page stress/regression fixtures - generation-time measurement - PDF-size measurement - browser-memory experiments - fresh-context memory isolation - repeated-generation testing - page-by-page incremental Canvas rendering - temporary DOM cleanup - canvas backing-store release - selectable repeated-image caching - cooperative browser yielding - cancellation and recovery - current-page / total-page progress - image-heavy and mixed-content scenarios - security, headers, footers, watermarks, metadata, compression, and links A diagnosed long Canvas capture was approximately: ```text 794 x 55,952 CSS px ``` At `html2canvas` scale 1.5 this corresponded to roughly 99.96 million raster pixels. The incremental page-bounded path uses captures around: ```text 1191 x 1461 ~1.74 million pixels per page ``` This is about a 98.26% smaller peak capture surface for that diagnosed case. This is a raster-surface geometry comparison, not a claim that total browser memory is 98.26% lower. ## Verified outcomes Final regression work verified: - 50-page Canvas generation - 100-page Canvas generation - Canvas cancellation and recovery - selectable-text cancellation and recovery - repeated-image caching in selectable-text mode - page-bounded Canvas rendering in image-heavy documents - temporary rendering cleanup Final unit suite: ```text 19 test files passed 106 / 106 unit tests passed ``` General E2E results: ```text 44 passed 2 skipped 2 Firefox timeouts under long suite load ``` Both Firefox failures passed when rerun individually. The large-document tests validate supported package paths and benchmark fixtures. They are not a universal guarantee for arbitrary HTML or every browser/device memory budget. ## Main component `Html2Pdf` The component renders HTML from the `pdf-content` slot and exposes PDF generation methods. Important methods: ```ts generatePdf(): Promise print(): Promise closePreview(): void resetPagination(): void cancelGeneration(): void ``` ## Slots - `pdf-content`: HTML rendered into the PDF - `loader`: Optional custom generation loader Loader slot state includes: - `progress` - `loading` - `stage` - `progressState` ## Events - `progress` - `progressStage` - `startPagination` - `hasPaginated` - `beforeDownload` - `hasDownloaded` - `closed` - `error` `progress` emits numeric generation progress. `progressStage` emits `PdfProgressState`. ## Core package API Important public exports include: - `Html2Pdf` - `Html2PdfLoader` - `useHtml2Pdf` - `generatePdf` - `createPdfOptions` - `normalizePdfFilename` - `paginateElement` - `resetPagination` - `addPdfWatermarks` - `mountWatermark` - `addPdfHeaders` - `addPdfFooters` - `resolvePdfPages` The package also exports TypeScript types for component props, PDF options, render mode, progress, security, metadata, headers, footers, watermarks, page targeting, and related configuration. ## Page targeting ```ts type PdfPageTarget = | 'all' | 'first' | 'last' | 'except-first' | number[] ``` Page targeting is currently used by: - Headers - Watermarks Footers continue to use all-page behavior. ## Filename normalization PDF filenames are normalized before generation. Behavior includes: - adds exactly one `.pdf` extension - prevents duplicate `.pdf` - sanitizes invalid filename/path characters - trims trailing dots and spaces - preserves Unicode - protects Windows-reserved names - limits excessively long base names - uses a timestamp fallback when empty ## Advanced configuration The package supports advanced configuration for: - html2pdf.js - html2canvas - jsPDF - image quality - page breaks - format - orientation - export width - CORS-aware images - raw metadata - raw compression - raw encryption where compatible High-level package props take priority over corresponding raw options when explicitly provided. ## Technology - vue - TypeScript - html2pdf.js - html2canvas - jsPDF - Vite - Vitest - Playwright ## Browser testing The package is tested with Playwright across: - Chromium - Firefox - WebKit WebKit represents the engine family used by Safari but is not identical to testing the Safari application itself. Heavy PDF stress/regression tests should use a low worker count. Recommended: ```bash npx playwright test --workers=1 ``` ## Notes for AI assistants and automated tools - This package targets vue, not Vue 2. - Default package render mode is `canvas`. - The live playground may choose selectable-text mode as its demonstration default. - Prefer `InstanceType` for typed component refs. - The manual page-break helper is `.html2pdf__page-break`. - Do not add `break-before` or `page-break-before` to that helper while legacy html2pdf page-break behavior is active. - Default no-break selectors include `.pdf-keep-together`, `.pdf-no-break`, and `img`. - Paginated Canvas documents with page-break markers use incremental page-by-page rendering. - Canvas documents without page-break markers retain the legacy html2pdf.js worker path. - Selectable-text mode emits real selectable/searchable/copyable PDF text for supported content. - Repeated real `` sources may be cached per generation in selectable-text mode. - `cancelGeneration()` requests cooperative cancellation. - `currentPage` and `totalPages` may be present in page-aware progress states. - Footer page numbering uses `{n}` and `{total}`. - There is no dedicated `pageNumbers` / page-numbering API. - Header page targeting and watermark targeting are independent. - Footers do not currently support independent page targeting. - `headerHtml` and `footerHtml` are trusted developer-controlled HTML and must not receive unsanitized user input. - `passwordParts` combine into a single open password. - Permission enforcement depends on the PDF viewer. - Large encrypted Canvas PDFs can retain substantially more memory in Chromium; see jsPDF issue #4017. - 100 pages is the current verified regression range, not a hard maximum page count. - Do not describe the source repository as open source; it is maintained privately. - Minification/obfuscation is not a security boundary. ## Funding If `vue-pdf-export` is useful, development can be supported at: [Buy me a coffee](https://buymeacoffee.com/saurabhzaiswal) ## License MIT License ## Author [Saurabh Choudhary](https://saurabhzaiswal.vercel.app/)