# jsPDF jsPDF is a leading open-source JavaScript library for generating PDF documents entirely in client-side JavaScript. It enables developers to create PDFs dynamically in web browsers or Node.js environments without server-side processing, supporting a wide range of features including text, images, shapes, forms, and HTML-to-PDF conversion. The library works across modern browsers and provides TypeScript support for type-safe development. The core functionality allows creating PDF documents with customizable page sizes, orientations, and measurement units. jsPDF supports embedding images (JPEG, PNG, GIF, BMP, WebP), drawing vector graphics (lines, rectangles, circles, curves), handling Unicode text with custom TTF fonts, creating interactive forms (AcroForms), and converting HTML content to PDF using html2canvas integration. The library provides both a "compat" API for basic operations and an "advanced" API for complex transformations and patterns. ## Creating a Basic PDF Document The `jsPDF` constructor creates a new PDF document instance with configurable options for page orientation, measurement units, and paper format. ```javascript import { jsPDF } from "jspdf"; // Create a default A4 portrait document using millimeters const doc = new jsPDF(); // Add text at position (10, 10) from top-left corner doc.text("Hello World!", 10, 10); // Save the document doc.save("hello-world.pdf"); // Create a landscape document with custom format const landscapeDoc = new jsPDF({ orientation: "landscape", unit: "in", format: [8.5, 11] // Custom size in inches }); landscapeDoc.text("Landscape Document", 1, 1); landscapeDoc.save("landscape.pdf"); // Create with encryption const secureDoc = new jsPDF({ encryption: { userPassword: "user123", ownerPassword: "owner456", userPermissions: ["print", "copy"] } }); secureDoc.text("Secure Content", 10, 10); secureDoc.save("secure.pdf"); ``` ## Adding and Formatting Text The `text()` method adds text to the document with support for alignment, rotation, multi-line text, and various formatting options. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Basic text at coordinates (x, y in mm) doc.text("Simple text", 10, 10); // Set font properties doc.setFontSize(16); doc.setFont("helvetica", "bold"); doc.setTextColor(255, 0, 0); // RGB: Red doc.text("Bold Red Title", 10, 20); // Multi-line text with alignment doc.setFontSize(12); doc.setFont("helvetica", "normal"); doc.setTextColor(0, 0, 0); doc.text("Left aligned text", 105, 40, { align: "left" }); doc.text("Centered text", 105, 50, { align: "center" }); doc.text("Right aligned text", 105, 60, { align: "right" }); // Rotated text (angle in degrees) doc.text("Rotated 45 degrees", 50, 100, { angle: 45 }); // Multi-line array const lines = ["Line 1", "Line 2", "Line 3"]; doc.text(lines, 10, 120); // Auto-wrap text with maxWidth const longText = "This is a very long text that will automatically wrap when it exceeds the specified maximum width."; doc.text(longText, 10, 150, { maxWidth: 80 }); // Justified text doc.text("This justified text spreads across the available width evenly.", 10, 180, { align: "justify", maxWidth: 80 }); doc.save("formatted-text.pdf"); ``` ## Adding Images The `addImage()` method embeds images in various formats (JPEG, PNG, GIF, WebP, BMP) with support for scaling, positioning, and compression. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Add image from base64 data const imgData = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD..."; doc.addImage(imgData, "JPEG", 10, 10, 50, 50); // x, y, width, height // Add image with compression doc.addImage(imgData, "JPEG", 10, 70, 100, 75, undefined, "FAST"); // Add image with rotation (degrees) doc.addImage(imgData, "JPEG", 120, 10, 50, 50, undefined, undefined, 45); // Add image using options object doc.addImage({ imageData: imgData, format: "JPEG", x: 10, y: 150, width: 80, height: 60, compression: "MEDIUM", rotation: 0 }); // Get image properties const props = doc.getImageProperties(imgData); console.log(`Image: ${props.width}x${props.height}, Format: ${props.fileType}`); // Add image from HTML canvas element const canvas = document.getElementById("myCanvas"); doc.addImage(canvas, "PNG", 10, 220, 100, 50); // Add image from URL (in browser) const img = new Image(); img.src = "https://example.com/image.png"; img.onload = function() { doc.addImage(img, "PNG", 10, 10, 100, 100); doc.save("with-images.pdf"); }; ``` ## Drawing Shapes and Lines jsPDF provides methods for drawing vector graphics including rectangles, circles, lines, and custom paths with fill and stroke options. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Set drawing colors doc.setDrawColor(0, 0, 255); // Blue stroke doc.setFillColor(255, 255, 0); // Yellow fill doc.setLineWidth(0.5); // Rectangle: x, y, width, height, style doc.rect(10, 10, 40, 20, "FD"); // F=fill, D=stroke, FD=both // Rounded rectangle with corner radii doc.roundedRect(60, 10, 40, 20, 3, 3, "FD"); // Circle: x, y, radius doc.setFillColor(0, 255, 0); doc.circle(130, 20, 15, "FD"); // Ellipse: x, y, rx, ry doc.setFillColor(255, 0, 255); doc.ellipse(180, 20, 20, 10, "FD"); // Line: x1, y1, x2, y2 doc.setDrawColor(255, 0, 0); doc.setLineWidth(1); doc.line(10, 50, 200, 50); // Triangle using lines doc.setFillColor(100, 100, 255); doc.triangle(30, 100, 10, 140, 50, 140, "FD"); // Custom path with bezier curves doc.setDrawColor(0, 0, 0); doc.setFillColor(255, 200, 100); doc.lines( [ [30, 0], // Line to relative position [0, 30], // Line down [10, 10, 20, 0, 30, -10], // Bezier curve (cp1x, cp1y, cp2x, cp2y, x, y) [-30, -20] // Line back ], 70, 80, // Starting point [1, 1], // Scale "FD", // Style true // Close path ); // Dashed line doc.setLineDashPattern([3, 2], 0); // [dash, gap], phase doc.line(10, 160, 200, 160); // Reset to solid line doc.setLineDashPattern([], 0); doc.save("shapes.pdf"); ``` ## Multi-Page Documents The `addPage()` and `setPage()` methods allow creating and navigating between multiple pages in a document. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // First page content doc.setFontSize(20); doc.text("Page 1 - Introduction", 10, 20); doc.setFontSize(12); doc.text("This is the first page of the document.", 10, 40); // Add a new page with same format doc.addPage(); doc.text("Page 2 - Content", 10, 20); // Add page with different format and orientation doc.addPage("a5", "landscape"); doc.text("Page 3 - A5 Landscape", 10, 20); // Add page with custom dimensions [width, height] doc.addPage([200, 100]); doc.text("Page 4 - Custom Size", 10, 20); // Navigate between pages doc.setPage(1); // Go back to first page doc.text("Added later to page 1", 10, 60); doc.setPage(2); doc.text("Additional content on page 2", 10, 40); // Get total page count const totalPages = doc.getNumberOfPages(); console.log(`Document has ${totalPages} pages`); // Add page numbers to all pages for (let i = 1; i <= totalPages; i++) { doc.setPage(i); doc.setFontSize(10); doc.text(`Page ${i} of ${totalPages}`, 105, 287, { align: "center" }); } // Delete a page doc.deletePage(3); // Remove page 3 // Insert page before another doc.insertPage(2); // Insert new page before page 2 doc.save("multipage.pdf"); ``` ## Using Custom Fonts (Unicode/UTF-8 Support) jsPDF supports custom TTF fonts for Unicode text rendering, enabling support for non-Latin characters and special symbols. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Method 1: Add font from base64 string (after using font converter) // First, convert TTF to base64 using: https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html const myFontBase64 = "AAEAAAALAIAAA..."; // Base64-encoded TTF data doc.addFileToVFS("MyFont.ttf", myFontBase64); doc.addFont("MyFont.ttf", "MyFont", "normal"); doc.setFont("MyFont"); doc.text("Custom font text with Unicode: ", 10, 20); // Method 2: Load font dynamically (browser) async function loadFontAndCreatePDF() { const doc = new jsPDF(); // Fetch font file const response = await fetch("./fonts/NotoSans-Regular.ttf"); const fontBuffer = await response.arrayBuffer(); const fontBase64 = btoa(String.fromCharCode(...new Uint8Array(fontBuffer))); // Add font to document doc.addFileToVFS("NotoSans-Regular.ttf", fontBase64); doc.addFont("NotoSans-Regular.ttf", "NotoSans", "normal"); // Use the font doc.setFont("NotoSans"); doc.setFontSize(14); // Now Unicode text renders correctly doc.text("English: Hello World!", 10, 20); doc.text("Chinese: ", 10, 35); doc.text("Japanese: ", 10, 50); doc.text("Arabic: ", 10, 65); doc.text("Russian: ", 10, 80); doc.save("unicode-text.pdf"); } // Standard fonts available without importing const doc2 = new jsPDF(); doc2.setFont("helvetica", "normal"); doc2.text("Helvetica Normal", 10, 10); doc2.setFont("helvetica", "bold"); doc2.text("Helvetica Bold", 10, 20); doc2.setFont("helvetica", "italic"); doc2.text("Helvetica Italic", 10, 30); doc2.setFont("times", "normal"); doc2.text("Times Roman", 10, 40); doc2.setFont("courier", "normal"); doc2.text("Courier", 10, 50); // List all available fonts const fontList = doc2.getFontList(); console.log("Available fonts:", fontList); // Output: { helvetica: ['normal', 'bold', 'italic', 'bolditalic'], times: [...], courier: [...] } doc2.save("standard-fonts.pdf"); ``` ## Converting HTML to PDF The `html()` method converts HTML elements or strings to PDF using html2canvas, supporting custom styling and pagination. ```javascript import { jsPDF } from "jspdf"; // Convert HTML element to PDF async function htmlElementToPDF() { const doc = new jsPDF(); const element = document.getElementById("content-to-print"); await doc.html(element, { callback: function(doc) { doc.save("from-html-element.pdf"); }, x: 10, y: 10, width: 180, // Target width in PDF windowWidth: 800, // Source window width for rendering autoPaging: "text", // Auto page break mode: 'text', 'slice', or false margin: [10, 10, 10, 10] // [top, right, bottom, left] margins }); } // Convert HTML string to PDF async function htmlStringToPDF() { const doc = new jsPDF("p", "mm", "a4"); const htmlContent = `

Report Title

This is a paragraph with bold and italic text.

NameValue
Alpha100
Beta200
`; await doc.html(htmlContent, { callback: function(doc) { doc.save("from-html-string.pdf"); }, x: 0, y: 0, width: 210, windowWidth: 800, html2canvas: { scale: 0.265, // Adjust scale for better quality useCORS: true, // Enable cross-origin images logging: false } }); } // HTML to PDF with custom fonts async function htmlWithCustomFonts() { const doc = new jsPDF(); await doc.html(document.getElementById("styled-content"), { callback: function(doc) { doc.save("styled-html.pdf"); }, fontFaces: [ { family: "CustomFont", src: [{ url: "./fonts/CustomFont.ttf", format: "truetype" }] } ], width: 180, windowWidth: 800 }); } // Call the functions htmlElementToPDF(); ``` ## Creating Interactive Forms (AcroForms) jsPDF supports creating interactive PDF forms with text fields, checkboxes, radio buttons, dropdowns, and buttons. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Add form title doc.setFontSize(18); doc.text("Registration Form", 105, 20, { align: "center" }); doc.setFontSize(12); // Text field const textField = new doc.AcroForm.TextField(); textField.fieldName = "fullName"; textField.x = 50; textField.y = 35; textField.width = 100; textField.height = 10; textField.defaultValue = "Enter your name"; textField.maxLength = 50; doc.addField(textField); doc.text("Full Name:", 10, 42); // Password field const passwordField = new doc.AcroForm.PasswordField(); passwordField.fieldName = "password"; passwordField.x = 50; passwordField.y = 50; passwordField.width = 100; passwordField.height = 10; doc.addField(passwordField); doc.text("Password:", 10, 57); // Multi-line text area const textArea = new doc.AcroForm.TextField(); textArea.fieldName = "comments"; textArea.x = 50; textArea.y = 65; textArea.width = 100; textArea.height = 30; textArea.multiline = true; doc.addField(textArea); doc.text("Comments:", 10, 72); // Checkbox const checkbox = new doc.AcroForm.CheckBox(); checkbox.fieldName = "agreeTerms"; checkbox.x = 50; checkbox.y = 105; checkbox.width = 10; checkbox.height = 10; doc.addField(checkbox); doc.text("I agree to terms:", 10, 112); // Radio buttons doc.text("Gender:", 10, 130); const radioGroup = new doc.AcroForm.RadioButton(); radioGroup.fieldName = "gender"; const maleOption = radioGroup.createOption("male"); maleOption.x = 50; maleOption.y = 123; maleOption.width = 10; maleOption.height = 10; doc.text("Male", 62, 130); const femaleOption = radioGroup.createOption("female"); femaleOption.x = 90; femaleOption.y = 123; femaleOption.width = 10; femaleOption.height = 10; doc.text("Female", 102, 130); doc.addField(radioGroup); // Dropdown (ComboBox) const dropdown = new doc.AcroForm.ComboBox(); dropdown.fieldName = "country"; dropdown.x = 50; dropdown.y = 140; dropdown.width = 100; dropdown.height = 10; dropdown.setOptions(["USA", "Canada", "UK", "Germany", "France", "Other"]); dropdown.defaultValue = "USA"; doc.addField(dropdown); doc.text("Country:", 10, 147); // List box (multiple selection) const listBox = new doc.AcroForm.ListBox(); listBox.fieldName = "interests"; listBox.x = 50; listBox.y = 155; listBox.width = 100; listBox.height = 25; listBox.setOptions(["Sports", "Music", "Technology", "Travel", "Art"]); listBox.multiSelect = true; doc.addField(listBox); doc.text("Interests:", 10, 162); // Push button const submitBtn = new doc.AcroForm.PushButton(); submitBtn.fieldName = "submitBtn"; submitBtn.x = 80; submitBtn.y = 190; submitBtn.width = 40; submitBtn.height = 12; submitBtn.caption = "Submit"; doc.addField(submitBtn); doc.save("interactive-form.pdf"); ``` ## Document Properties and Metadata jsPDF allows setting document metadata including title, author, subject, keywords, and various viewer preferences. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Set document properties/metadata doc.setDocumentProperties({ title: "Annual Report 2024", subject: "Financial Summary", author: "John Doe", keywords: "finance, report, annual, 2024", creator: "MyApp v1.0" }); // Set creation date doc.setCreationDate(new Date("2024-01-15")); // Set display mode when PDF opens doc.setDisplayMode( "fullwidth", // Zoom: 'fullwidth', 'fullheight', 'fullpage', 'original', or number/% "continuous", // Layout: 'continuous', 'single', 'twoleft', 'tworight' "UseOutlines" // Page mode: 'UseNone', 'UseOutlines', 'UseThumbs', 'FullScreen' ); // Set viewer preferences doc.viewerPreferences({ HideToolbar: false, HideMenubar: false, HideWindowUI: false, FitWindow: true, CenterWindow: true, DisplayDocTitle: true, NonFullScreenPageMode: "UseOutlines", Direction: "L2R", PrintScaling: "None", Duplex: "DuplexFlipLongEdge" }); // Add content doc.text("Document with metadata and viewer settings", 10, 20); // Get document info const creationDate = doc.getCreationDate("jsDate"); console.log("Created:", creationDate); const fileId = doc.getFileId(); console.log("File ID:", fileId); doc.save("with-metadata.pdf"); ``` ## Output Formats and Saving The `output()` method provides various output formats including raw string, ArrayBuffer, Blob, data URI, and direct save options. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); doc.text("Output Example", 10, 10); // Output as raw PDF string const pdfString = doc.output(); console.log("PDF string length:", pdfString.length); // Output as ArrayBuffer (useful for sending to server) const arrayBuffer = doc.output("arraybuffer"); console.log("ArrayBuffer size:", arrayBuffer.byteLength); // Output as Blob const blob = doc.output("blob"); console.log("Blob size:", blob.size); // Output as Blob URL (for preview in iframe) const blobUrl = doc.output("bloburl"); document.getElementById("preview-frame").src = blobUrl; // Output as data URI string const dataUri = doc.output("datauristring", { filename: "preview.pdf" }); console.log("Data URI starts with:", dataUri.substring(0, 50)); // Open in new window using data URI doc.output("dataurlnewwindow", { filename: "newwindow.pdf" }); // Navigate current window to PDF // doc.output("dataurl", { filename: "navigate.pdf" }); // Save with default filename doc.save("document.pdf"); // Save with Promise (useful for async workflows) doc.save("async-document.pdf", { returnPromise: true }) .then(() => { console.log("PDF saved successfully!"); }) .catch((error) => { console.error("Save failed:", error); }); // Node.js: File is saved to current working directory // Browser: File is downloaded via FileSaver.js ``` ## Advanced API: Transformations and Graphics State The advanced API mode enables complex transformations, patterns, and graphics state management for sophisticated PDF generation. ```javascript import { jsPDF, GState, ShadingPattern, TilingPattern } from "jspdf"; const doc = new jsPDF(); // Switch to advanced API mode doc.advancedAPI(doc => { // Matrix transformations doc.saveGraphicsState(); // Apply transformation matrix: scale, rotate, translate const matrix = new doc.Matrix(1, 0, 0, 1, 50, 50); // Translate to (50, 50) doc.setCurrentTransformationMatrix(matrix); doc.setFillColor(255, 0, 0); doc.rect(0, 0, 30, 30, "F"); doc.restoreGraphicsState(); // Graphics state with opacity const gState = new GState({ opacity: 0.5 }); doc.setGState(gState); doc.setFillColor(0, 0, 255); doc.rect(60, 60, 40, 40, "F"); // Reset opacity doc.setGState(new GState({ opacity: 1.0 })); }); // Create gradient pattern (advanced API) doc.advancedAPI(doc => { // Linear gradient const linearGradient = new ShadingPattern("axial", [0, 0, 100, 0], // x1, y1, x2, y2 [ { offset: 0, color: [255, 0, 0] }, // Red at start { offset: 0.5, color: [255, 255, 0] }, // Yellow at middle { offset: 1, color: [0, 255, 0] } // Green at end ] ); doc.addShadingPattern("myGradient", linearGradient); doc.rect(10, 120, 100, 50, null); // Create path without drawing doc.fill({ key: "myGradient", matrix: doc.unitMatrix }); // Radial gradient const radialGradient = new ShadingPattern("radial", [50, 50, 0, 50, 50, 40], // x1, y1, r1, x2, y2, r2 [ { offset: 0, color: [255, 255, 255] }, { offset: 1, color: [0, 0, 128] } ] ); doc.addShadingPattern("radialGrad", radialGradient); doc.circle(150, 145, 30, null); doc.fill({ key: "radialGrad", matrix: doc.unitMatrix }); }); // Clipping paths doc.saveGraphicsState(); doc.circle(50, 230, 25, null); doc.clip(); doc.discardPath(); // Draw image that gets clipped to circle doc.setFillColor(100, 200, 100); doc.rect(20, 200, 60, 60, "F"); doc.restoreGraphicsState(); doc.save("advanced-graphics.pdf"); ``` ## Working with Outlines and Bookmarks The outline plugin enables creating a navigable table of contents with hierarchical bookmarks in the PDF document. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Page 1: Title page doc.setFontSize(24); doc.text("Complete Guide", 105, 50, { align: "center" }); // Page 2: Chapter 1 doc.addPage(); doc.setFontSize(18); doc.text("Chapter 1: Introduction", 10, 20); doc.setFontSize(12); doc.text("Welcome to the guide. This chapter covers basics.", 10, 35); // Page 3: Chapter 1 subsection doc.addPage(); doc.text("1.1 Getting Started", 10, 20); // Page 4: Chapter 2 doc.addPage(); doc.setFontSize(18); doc.text("Chapter 2: Advanced Topics", 10, 20); // Page 5: Chapter 2 subsection doc.addPage(); doc.text("2.1 Complex Features", 10, 20); // Create outline/bookmarks const root = doc.outline.add(null, "Table of Contents", { pageNumber: 1 }); const ch1 = doc.outline.add(root, "Chapter 1: Introduction", { pageNumber: 2 }); doc.outline.add(ch1, "1.1 Getting Started", { pageNumber: 3 }); const ch2 = doc.outline.add(root, "Chapter 2: Advanced Topics", { pageNumber: 4 }); doc.outline.add(ch2, "2.1 Complex Features", { pageNumber: 5 }); // Set to display outlines when opened doc.setDisplayMode(null, null, "UseOutlines"); doc.save("with-bookmarks.pdf"); ``` ## Tables and Cell Layout The cell plugin provides methods for creating tables with automatic sizing and pagination. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Simple table using cell method doc.setFontSize(10); // Header row doc.setFillColor(200, 200, 200); doc.cell(10, 10, 50, 10, "Name", 0, "center"); doc.cell(60, 10, 40, 10, "Age", 0, "center"); doc.cell(100, 10, 50, 10, "City", 0, "center"); // Data rows doc.setFillColor(255, 255, 255); doc.cell(10, 20, 50, 10, "John Doe", 1, "left"); doc.cell(60, 20, 40, 10, "28", 1, "center"); doc.cell(100, 20, 50, 10, "New York", 1, "left"); doc.cell(10, 30, 50, 10, "Jane Smith", 2, "left"); doc.cell(60, 30, 40, 10, "34", 2, "center"); doc.cell(100, 30, 50, 10, "Los Angeles", 2, "left"); // Using table() method for automatic formatting const headers = [ { name: "id", prompt: "ID", width: 30, align: "center", padding: 2 }, { name: "name", prompt: "Product Name", width: 65, align: "left", padding: 2 }, { name: "price", prompt: "Price ($)", width: 35, align: "right", padding: 2 }, { name: "qty", prompt: "Quantity", width: 35, align: "center", padding: 2 } ]; const data = [ { id: "001", name: "Widget A", price: "19.99", qty: "150" }, { id: "002", name: "Widget B", price: "29.99", qty: "75" }, { id: "003", name: "Gadget X", price: "49.99", qty: "200" }, { id: "004", name: "Gadget Y", price: "99.99", qty: "50" }, { id: "005", name: "Tool Z", price: "14.99", qty: "300" } ]; doc.table(10, 60, data, headers, { fontSize: 10, padding: 3, headerBackgroundColor: "#4472C4", headerTextColor: "#FFFFFF", autoSize: false, printHeaders: true }); // Get text dimensions for custom layouts const dimensions = doc.getTextDimensions("Sample Text", { fontSize: 12 }); console.log(`Text width: ${dimensions.w}, height: ${dimensions.h}`); doc.save("tables.pdf"); ``` ## Adding JavaScript and Auto-Print jsPDF supports embedding JavaScript for actions and setting auto-print behavior when the PDF opens. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); doc.text("This document will print automatically when opened.", 10, 20); // Method 1: Auto-print using JavaScript doc.autoPrint({ variant: "javascript" }); // Method 2: Auto-print using non-conforming method (wider support) // doc.autoPrint({ variant: "non-conform" }); // Add custom JavaScript doc.addJS(` app.alert("Welcome to the PDF document!"); // Display document info var info = this.info; console.println("Title: " + info.Title); console.println("Author: " + info.Author); `); // Set document title for the JavaScript to access doc.setDocumentProperties({ title: "Auto-Print Document", author: "PDF Generator" }); doc.save("auto-print.pdf"); ``` ## Working with Annotations and Links The annotations plugin enables adding text annotations, links, and clickable areas to PDF documents. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // Add text with a link doc.setFontSize(12); doc.textWithLink("Visit Google", 10, 20, { url: "https://www.google.com" }); // Internal link to another page doc.addPage(); doc.text("Page 2: Target Section", 10, 20); doc.setPage(1); doc.textWithLink("Go to Page 2", 10, 35, { pageNumber: 2 }); // Create link area (invisible clickable region) doc.link(10, 50, 50, 10, { url: "https://www.example.com" }); doc.text("Click here for example.com", 10, 55); // Text annotation (popup note) doc.createAnnotation({ type: "text", title: "Note", bounds: { x: 10, y: 70, w: 30, h: 30 }, contents: "This is an important note about the document.", open: false, color: "#FFFF00", name: "Comment" }); doc.text("Hover over the icon for a note", 45, 80); // Free text annotation (text directly on page) doc.createAnnotation({ type: "freetext", bounds: { x: 10, y: 100, w: 100, h: 20 }, contents: "This is a free text annotation", color: "#FF0000" }); // Get text width for precise link positioning const linkText = "GitHub Repository"; const textWidth = doc.getTextWidth(linkText); doc.text(linkText, 10, 140); doc.link(10, 135, textWidth, 10, { url: "https://github.com/parallax/jsPDF" }); doc.save("with-annotations.pdf"); ``` ## SVG to PDF Conversion The SVG plugin allows embedding SVG images directly into PDF documents with full vector quality. ```javascript import { jsPDF } from "jspdf"; const doc = new jsPDF(); // SVG as string const svgString = ` SVG `; // Add SVG to PDF doc.addSvgAsImage( svgString, 10, // x position 10, // y position 50, // width 50, // height undefined, // alias false, // compression 0 // rotation ); // Multiple SVG elements const shapes = ` `; doc.addSvgAsImage(shapes, 10, 70, 100, 50); // SVG from DOM element (browser) const svgElement = document.querySelector("#my-svg"); if (svgElement) { const svgData = new XMLSerializer().serializeToString(svgElement); doc.addSvgAsImage(svgData, 10, 130, 80, 80); } doc.save("with-svg.pdf"); ``` ## Running in Node.js jsPDF works in Node.js for server-side PDF generation, automatically using file system operations instead of browser APIs. ```javascript // CommonJS syntax for Node.js const { jsPDF } = require("jspdf"); // Create document const doc = new jsPDF(); // Security: Restrict file access (recommended) // Use Node's permission flags: node --permission --allow-fs-read=./fonts,./images ./script.js // Alternative: Whitelist specific paths (less secure) doc.allowFsRead = ["./fonts/*", "./images/logo.png"]; // Add content doc.setFontSize(20); doc.text("Server-generated PDF", 10, 20); doc.setFontSize(12); const timestamp = new Date().toISOString(); doc.text(`Generated at: ${timestamp}`, 10, 35); // Load and embed image from file system const fs = require("fs"); const path = require("path"); // Read image as base64 const imagePath = path.join(__dirname, "logo.png"); if (fs.existsSync(imagePath)) { const imageData = fs.readFileSync(imagePath); const base64Image = imageData.toString("base64"); doc.addImage(base64Image, "PNG", 10, 50, 50, 50); } // Save to file system (synchronous) doc.save("server-output.pdf"); // Saves to current working directory // Save with Promise (asynchronous) doc.save("async-output.pdf", { returnPromise: true }) .then(() => console.log("PDF saved successfully")) .catch(err => console.error("Error saving PDF:", err)); // Get as buffer for HTTP response const pdfBuffer = Buffer.from(doc.output("arraybuffer")); // Example: Express.js response /* app.get("/generate-pdf", (req, res) => { const doc = new jsPDF(); doc.text("Dynamic PDF", 10, 10); const buffer = Buffer.from(doc.output("arraybuffer")); res.set({ "Content-Type": "application/pdf", "Content-Disposition": "attachment; filename=download.pdf", "Content-Length": buffer.length }); res.send(buffer); }); */ ``` jsPDF is an essential library for client-side PDF generation in JavaScript applications. It supports a comprehensive range of features from basic text and image placement to advanced form creation, HTML conversion, and vector graphics. The library's modular plugin architecture allows developers to include only the features they need, keeping bundle sizes manageable. Common integration patterns include generating invoices and reports from application data, converting web content to downloadable PDFs, creating fillable forms for user input, and building document templates with dynamic content. The library works seamlessly with popular frameworks like React, Angular, and Vue, and its Node.js support enables server-side PDF generation for applications requiring backend processing or batch document creation.