Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
If jsPDF captures the whole document.body instead of the section you want, the most reliable fix is to stop using the deprecated addHTML() method, select the target element explicitly, and use the maintained html() rendering path supported by your installed jsPDF version. Verify the element before rendering, then test DOM-to-canvas capture separately from PDF creation. A body-only result can also come from a mismatched legacy dependency, browser resource restrictions, or canvas limits, so the correct diagnosis depends on your selector, package versions, and runtime.
Why addHTML() captures document.body
addHTML() and fromHTML() are deprecated jsPDF APIs. The jsPDF maintainers introduced html(), based on html2canvas and the project’s context2d module, as the maintained HTML-rendering path. Older examples often pass document.body, rely on implicit defaults, or combine an old jsPDF plugin with a newer html2canvas release. Any of those patterns can produce output that appears to contain the entire page, the wrong node, a blank page, or incomplete content.
There is no single confirmed cause for every body-only report. Treat the symptom as a debugging branch: prove which node you selected, prove what the browser rendered to a canvas, and only then debug PDF placement and pagination.
First check: select and verify the exact element
Use a unique selector for the printable region. Do not pass document, window, or document.body unless the entire page is genuinely the intended document.
#1 Best Overall
- Scanner type: Document
- Connectivity technology: USB
- With Auto Scan Mode, the scanner automatically detects what you're scanning
- Digitize documents and images
const target = document.querySelector('#pdf-content');
if (!target) {
throw new Error('PDF target not found');
}
console.log({
tag: target.tagName,
id: target.id,
className: target.className,
text: target.textContent.slice(0, 120)
});
Run this in the same event handler that starts PDF generation. In DevTools, expand the logged node and confirm that it contains the heading, table, images, and other content you expect. A selector that matches a wrapper around the whole application, or a selector that is evaluated before a component mounts, can look like a jsPDF failure even though the wrong element was supplied.
Common selector mistakes
- The ID is duplicated, so
querySelector()returns the first copy. - The target is rendered later by React, Vue, or another framework, but the export runs before the node exists.
- A button is inside the target and its click handler changes the DOM while capture is starting.
- The selector points to a layout wrapper whose children are outside it, rather than to the visible report container.
- CSS hides the target or its descendants at capture time.
Replace addHTML() with the supported html() method
Use the html() method documented for your installed jsPDF release and pass the verified DOM element. The exact option names and completion behavior vary by release, so check the API documentation shipped with that version instead of copying a signature from an unrelated example.
import { jsPDF } from 'jspdf';
async function exportReport() {
const target = document.querySelector('#pdf-content');
if (!target) throw new Error('PDF target not found');
const pdf = new jsPDF({
unit: 'pt',
format: 'a4',
orientation: 'portrait'
});
await pdf.html(target, {
// Set options supported by your installed jsPDF version.
// Use the documented completion callback or Promise behavior.
});
pdf.save('report.pdf');
}
document.querySelector('#export').addEventListener('click', exportReport);
Some releases expose completion through a callback rather than a Promise. If your installed version does, put pdf.save() inside that documented callback. Do not infer compatibility from the package name alone: record the exact jsPDF, html2canvas, and html2pdf.js versions in your project lockfile and follow the API for that combination.
Recommended Free Tools
Isolate HTML capture from PDF generation
html2canvas accepts a DOM element and returns a Promise that resolves to a canvas. Testing it independently tells you whether the wrong content is produced before jsPDF is involved.
import html2canvas from 'html2canvas';
async function inspectCapture() {
const target = document.querySelector('#pdf-content');
if (!target) throw new Error('PDF target not found');
const canvas = await html2canvas(target, {
backgroundColor: '#ffffff',
useCORS: true
});
document.body.appendChild(canvas);
console.log(canvas.width, canvas.height);
}
inspectCapture().catch(console.error);
If the appended canvas already shows the complete page, inspect the selector, computed styles, cloned DOM, and browser timing. If the canvas contains only the intended report but the PDF is wrong, focus on jsPDF’s HTML method, page sizing, margins, scaling, and completion callback.
Rank #2
- PORTABLE SCANNER FOR USE ON-THE-GO — The fastest and lightest mobile single-sheet-fed compact document scanner in its class¹
- QUICK DOCUMENT SCANNING ― This Epson ultra-fast scanner scans a single page as quickly as 5.5 seconds²; Windows and Mac compatible
- VERSATILE PAPER HANDLING ― Portable scanner scans documents up to 8.5 x 72 in; Also easily digitizes receipts and ID cards to make accounting, bookkeeping, and organizing simpler
- INTUITIVE, HIGH-SPEED SOFTWARE — Epson ScanSmart Software³ is a smart tool allowing you to easily scan, review, and save; Stay organized easily with the help of this Epson scanner
- EASY SETUP — USB-powered connect to your computer for quick and simple scanning; No batteries or external power supply required to operate portable document scanner; Standard Connectivity: USB 2.0
Wait for content before capturing
Images, fonts, charts, and framework updates may not be ready when export begins. Disable the export button while a capture is running, wait for data and images, and capture after the next render cycle when necessary.
await document.fonts.ready;
await new Promise(requestAnimationFrame);
const images = [...document.querySelectorAll('#pdf-content img')];
await Promise.all(images.map(img => {
if (img.complete) return Promise.resolve();
return new Promise(resolve => {
img.addEventListener('load', resolve, { once: true });
img.addEventListener('error', resolve, { once: true });
});
}));
Legacy dependencies and callback failures
Historical jsPDF issue discussions describe callback problems when older addHTML() integrations were paired with html2canvas 1.0.0-alpha.10. html2canvas moved toward a Promise-based API, while older wrappers expected a callback. This history is useful for identifying an integration mismatch, but it is not a definitive diagnosis for a current project.
- Print the installed versions from your package manager or lockfile.
- Remove duplicate copies loaded by script tags and bundlers.
- Use the jsPDF
html()method and the completion mechanism documented for that release. - If you must keep legacy code temporarily, pin a compatible dependency set rather than mixing an old plugin with an unrelated latest package.
- Retest after clearing the browser cache and rebuilding the bundle.
When using html2pdf.js as a separate workflow, its documented pattern is to select a node and call html2pdf(element). The bundled distribution includes its dependencies. With unbundled scripts, load jsPDF first, then html2canvas, then html2pdf.js; changing that order can leave methods undefined or connect the wrong library instance.
Cross-origin images, fonts, and browser limits
html2canvas runs inside the browser. It does not bypass the browser’s same-origin rules. Images or other resources served without appropriate cross-origin permission can taint the canvas, disappear, or cause the export to fail. Serve assets from the same origin, configure the asset server for cross-origin use, or replace inaccessible remote images with data URLs generated by your own backend.
Also check:
- Images have finished loading and have usable dimensions.
- Web fonts are loaded before capture; otherwise text can reflow or use a fallback font.
- CSS filters, videos, embedded documents, and complex SVG features may not render identically to the live page.
- Very large or very tall canvases can exceed browser canvas dimensions or memory limits.
- html2pdf.js clones the source DOM; clone-specific styles, fixed positioning, and overflow rules can change the result.
For long reports, split content into deliberate sections or pages instead of creating one enormous canvas. This reduces memory pressure and makes page breaks easier to control.
Rank #3
- FAST SPEEDS - Scans color and black and white documents a blazing speed up to 16ppm (1). Color scanning won’t slow you down as the color scan speed is the same as the black and white scan speed.
- ULTRA COMPACT – At less than 1 foot in length and only about 1. 5lbs in weight you can fit this device virtually anywhere (a bag, a purse, even a pocket).
- READY WHENEVER YOU ARE – The DS-640 mobile scanner is powered via an included micro USB 3. 0 cable allowing you to use it even where there is no outlet available. Plug it into you PC or laptop and you are ready to scan.
- WORKS YOUR WAY – Use the Brother free iPrint&Scan desktop app for scanning to multiple “Scan-to” destinations like PC, Network, cloud services, Email and OCR. (2) Supports Windows, Mac and Linux and TWAIN/WIA for PC/ICA for Mac/SANE drivers. (3)
- OPTIMIZE IMAGES AND TEXT – Automatic color detection/adjustment, image rotation (PC only), bleed through prevention/background removal, text enhancement, color drop to enhance scans. Software suite includes document management and OCR software. (4)
Choosing between jsPDF html() and html2pdf.js
| Question | jsPDF html() |
html2pdf.js |
|---|---|---|
| Input | Pass a DOM element; confirm the signature for your installed jsPDF release. | README examples select a node and call html2pdf(element). |
| Rendering model | Uses html2canvas and jsPDF’s HTML/context2d integration. | Builds an image-based PDF workflow. |
| Text search and selection | Depends on the release and rendering path. | Rasterized output can make text non-selectable and non-searchable. |
| Page breaks | Use options documented by your jsPDF version. | Documents page-break controls, but clone and canvas-size limits still apply. |
| Environment | Browser rendering is required for HTML capture. | Browser-only; it is not a server-side HTML renderer. |
Choose based on your exact package versions, CSS and font requirements, image access, pagination needs, and whether rasterized text is acceptable. Neither library guarantees pixel-identical output for every browser feature.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Troubleshooting by symptom
The PDF contains the whole application
Log the value immediately before rendering. Replace a broad selector such as body or an app root with a unique report selector. Confirm that the target’s parent is not the only element containing the report because of portal rendering.
The canvas is wrong before jsPDF runs
Fix DOM selection, timing, visibility, fonts, images, and cross-origin resources first. jsPDF cannot correct a canvas that already contains the wrong pixels.
The canvas is correct but the PDF is blank
Check that you are calling html() on the same jsPDF instance, that the method exists in the installed build, and that save() runs only after rendering completes. A legacy callback or an incompatible plugin can leave the PDF empty.
Only the first page appears
Inspect the target height and the method’s page-break and margin options. Reduce oversized elements, avoid unbroken giant canvases, and test a short report before adding tables, charts, and images.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Rank #4
- FAST DOCUMENT SCANNING — Document scanner with feeder allows you to speed through stacks with a 50-sheet Auto Document Feeder (ADF); Efficient office scanner to help you scan more productively
- INTUITIVE, HIGH-SPEED SOFTWARE — Quickly scan with this desktop document scanner; Epson ScanSmart Software lets you easily preview scans, email files, upload to the cloud, and more; Plus, automatic file naming saves even more time
- SEAMLESS INTEGRATION — Easily incorporate your data into most document management software with the included TWAIN driver; Office document scanner integrates seamlessly with business workflows
- EASY SHARING — Duplex scanner allows you to scan straight to email or popular cloud storage2 services like Dropbox, Evernote, Google Drive, and OneDrive for simple storage and sharing
- SIMPLE FILE MANAGEMENT — Scanner allows the creation of searchable PDFs with Optical Character Recognition (OCR) and convert scans to editable Word or Excel files effortlessly; Designed for home and office document scanning
Images are missing
Open the image URL directly, verify its response headers and dimensions, wait for loading, and address same-origin or cross-origin restrictions. A browser screenshot can show an image that a canvas is not permitted to read.
The export works locally but not in production
Compare asset origins, content-security policy, font URLs, bundler versions, and the production browser. Reproduce with a minimal page containing one heading and one same-origin image, then add features one at a time.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Performance and reliability checklist
- Capture a dedicated report container, not the application shell.
- Wait for data, fonts, images, and chart rendering.
- Use a white background when transparent or inherited backgrounds would reduce readability.
- Keep image dimensions and report height within browser canvas limits.
- Run exports in a user gesture and show progress for large documents.
- Log package versions and browser details with failures.
- Test Chrome, Firefox, and the browsers your users actually support.
- Compare the generated PDF with the inspected canvas so placement bugs are not confused with capture bugs.
Or skip the browser setup
If your goal is a reliable URL screenshot or PDF rather than debugging a browser bundle, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Only clean shots are billed: bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status.
One GET request is enough:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for all options, including PNG, JPEG, WebP, PDF, full-page lazy-image loading, CSS-selector element capture, device and retina settings, custom CSS or JavaScript, waits, request blocking, cookies and headers, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous webhooks, bulk capture, and the usage API.
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also includes an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Should I keep using addHTML() if it works in my current build?
No for new code. Move to the html() path documented for your installed jsPDF release, then remove the deprecated call after testing.
Best Value
- FITS SMALL SPACES AND STAYS OUT OF THE WAY. Innovative space-saving design to free up desk space, even when it's being used
- SCAN DOCUMENTS, PHOTOS, CARDS, AND MORE. Handles most document types, including thick items and plastic cards. Exclusive QUICK MENU lets you quickly scan-drag-drop to your favorite computer apps
- GREAT IMAGES EVERY TIME, NO EXPERIENCE REQUIRED. A single touch starts fast, up to 30ppm duplex scanning with automatic de-skew, color optimization, and blank page removal for outstanding results without driver setup
- SCAN WHERE YOU WANT, WHEN YOU WANT. Connect with USB or Wi-Fi. Send to Mac, PC, mobile devices, and cloud services. Scan to Chromebook using the mobile app. Can be used without a computer
- PHOTO AND DOCUMENT ORGANIZATION MADE EFFORTLESS. ScanSnap Home all-in-one software brings together all your favorite functions. Easily manage, edit, and use scanned data from documents, receipts, business cards, photos, and more
Can html2canvas capture an HTML string instead of an element?
Its documented browser call accepts a DOM element. Convert your markup into a mounted element first, then pass that node.
Why does the live page show an image while the PDF does not?
Canvas capture is subject to browser cross-origin rules and resource timing. Check the image origin, response permissions, dimensions, and load completion.
Is html2pdf.js server-side?
No. Its documented workflow is browser-only and depends on DOM and canvas rendering.
The Bottom Line
Verify the target node, replace deprecated addHTML() with the version-appropriate html() method, and inspect an html2canvas result before debugging PDF layout. That sequence distinguishes selector and browser-rendering problems from jsPDF integration problems.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

