The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use a React ref to target the rendered component, then pass that DOM node to jsPDF’s html() method from a user action. jsPDF renders the element through html2canvas, so the result is a browser-side reconstruction of your HTML and CSS rather than a literal screenshot. When rendering finishes, save the document in the callback.
This approach is practical when you already have a styled React view and want a download button. It is not print-perfect for every CSS rule, image origin, font, or very long layout. The complete setup below shows the reliable baseline, then covers fidelity limits, security, alternatives, and failure recovery.
Install the packages
Install jsPDF in the React project. The html() path also depends on html2canvas, so install it explicitly when your package manager does not bring it in with your chosen jsPDF build.
Free tools Windows power users keep installed
One-click scans. No signup required.
npm install jspdf html2canvas
Confirm the import syntax against the exact jsPDF version in your lockfile. The current documentation demonstrates a named jsPDF import, but bundler interop can differ between releases and build tools.
#1 Best Overall
Build the basic React export
The ref must point to the element that is actually rendered. Put only document content inside that element; keep navigation, buttons, loading indicators, and other transient controls outside it.
import { useRef } from 'react';
import { jsPDF } from 'jspdf';
function Report() {
const reportRef = useRef(null);
const downloadPdf = () => {
const element = reportRef.current;
if (!element) return;
const doc = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4',
});
doc.html(element, {
callback: (pdf) => pdf.save('report.pdf'),
margin: [10, 10, 10, 10],
autoPaging: 'text',
});
};
return (
<>
<section ref={reportRef}>
<h1>Report</h1>
<p>Content to export</p>
</section>
<button type="button" onClick={downloadPdf}>
Download PDF
</button>
</>
);
}
export default Report;
The click handler runs after React has mounted the section, so reportRef.current is a DOM node rather than null. The callback is important: saving there waits for the asynchronous HTML rendering to finish. The example requests A4 portrait pages in millimetres, 10 mm margins, and text-aware automatic paging.
Keep the export surface deliberate
Render an export-only wrapper when the on-screen component contains controls or responsive chrome. You can duplicate the data into a print layout, hide elements with export-specific CSS, or conditionally omit them before calling html(). A smaller, purpose-built DOM tree usually produces more predictable pagination than capturing an entire application shell.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Choose page geometry and rendering options
jsPDF creates the document before it renders the node. Set these values intentionally rather than relying on defaults:
Rank #2
| Setting | What it controls | Practical choice |
|---|---|---|
orientation |
Page direction | 'portrait' for reports; 'landscape' for wide tables |
unit |
Coordinates and margins | 'mm' is convenient for paper measurements |
format |
Paper size | 'a4', or another format supported by your installed release |
margin |
Whitespace around rendered content | Use an array such as [10, 10, 10, 10] and test the target browser |
autoPaging |
How HTML content is split across pages | 'text' can reduce awkward text cuts; verify complex layouts |
For exact page composition, jsPDF’s drawing API is more deterministic than converting arbitrary DOM. You can create pages, place text and graphics at known coordinates, and call save() yourself. That is more work, but it avoids depending on browser layout reconstruction.
What jsPDF’s HTML path really does
The html() method uses html2canvas. html2canvas rebuilds a visual representation from DOM information; it does not take a literal screenshot of the browser surface. CSS that html2canvas does not support, pseudo-elements with unusual behavior, filters, some transforms, and complex responsive interactions may therefore appear differently in the PDF. The html2canvas documentation lists its support and limitation details at https://html2canvas.github.io/html2canvas/documentation/.
Inspect the generated file in every browser you support. If a particular card, chart, or table is important, simplify its CSS for export or create an export-only variant. There are no universal fidelity or speed guarantees for arbitrary React layouts, and the available project documentation does not provide a cross-browser performance benchmark.
Images, fonts, and cross-origin resources
Remote images and other resources must be available to the browser under normal web security rules. Cross-origin images can be skipped or taint the canvas unless the server supplies suitable CORS permissions. Configure the asset server for the required origin, serve assets from the same origin, or use a controlled proxy where appropriate. html2canvas cannot bypass content-security or cross-origin restrictions; its getting-started guidance explains the browser prerequisites at https://html2canvas.github.io/html2canvas/getting-started/.
Fonts deserve the same check. jsPDF’s standard 14 fonts have limited ASCII coverage. If your report contains accented characters, non-Latin scripts, or symbols outside that range, embed a custom TTF containing the required glyphs and verify the result in the generated PDF. Do not assume that a font loaded by CSS will automatically become an embedded PDF font.
Long documents and page breaks
Long, nested layouts are where DOM-to-PDF conversion needs the most testing. Break content into logical blocks, avoid huge fixed-height containers, and check headings that land at the bottom of a page. Use an export stylesheet to reduce oversized margins and animations. The autoPaging option helps, but it is not a guarantee that every flex, grid, positioned element, or table will break as a human would expect.
Run conversion only after the content is ready
Do not invoke conversion while data is still loading. Disable the button until the report query, images, and fonts needed by the export have finished. If a component changes immediately before the click, let React commit that update first (for example, by enabling the button only after the ready state is true). A ref identifies the current node; it does not wait for asynchronous application data.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsFor interactive widgets, capture a stable state. Close menus, stop animations, and replace canvas-based charts with a deterministic export representation when necessary. A loading spinner or blinking cursor can otherwise become part of the PDF.
Rank #4
Security and text handling
Sanitize untrusted content before rendering it into the component and before passing it to jsPDF. The jsPDF documentation states: “We strongly advise you to sanitize user input before passing it to jsPDF!” Treat report data, HTML fragments, URLs, and filenames as untrusted. Avoid injecting raw markup merely to make export work, and validate any user-controlled values used in custom drawing code.
Sanitization does not solve cross-origin problems or guarantee safe CSS. Keep the export component’s styles and resource URLs under your control, and test with the same content classes your users can submit.
Browser-only limitation
This html2canvas-based workflow runs in a browser because it needs a DOM and browser rendering APIs. It is not suitable for a Node.js-only process or a server function with no browser environment. If your requirement is server-side generation, use a PDF-native renderer or a browser-capable service rather than calling this DOM path in plain Node.js.
Alternatives when DOM reuse is not the priority
React PDF
React PDF uses PDF-specific React components such as Document, Page, and Text. Its web documentation also provides PDFDownloadLink. You describe the PDF layout directly instead of asking html2canvas to interpret an existing DOM tree. This is a better fit when pagination and typography must be designed as a document, but it requires a separate component tree and styling model. See the v2 component documentation at https://react-pdf.org/docs/v2/components.
Best Value
html2pdf.js
html2pdf.js packages a client-side element-to-PDF workflow around html2canvas and jsPDF. Its README states that it must run in a browser: https://github.com/eKoopmans/html2pdf.js/. It can be convenient when you prefer its chaining API, but it inherits the same fundamental DOM reconstruction and cross-origin limitations.
| Requirement | DOM capture with jsPDF | PDF-native React components |
|---|---|---|
| Reuse existing HTML and CSS | Strong fit | Requires a separate document tree |
| Exact pagination and coordinates | Needs testing and export-specific CSS | More explicit control |
| Browser-only download | Yes | Web download components are available |
| Server-only Node execution | Not suitable | Choose an implementation that supports your deployment target |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Nothing downloads | The ref is null or saving occurs before rendering completes | Call from a user action after mount and place pdf.save() inside the callback. |
| Images are missing | Cross-origin response lacks suitable CORS headers, or the image is not loaded yet | Serve the asset with appropriate CORS, use same-origin hosting or a controlled proxy, and wait until images are ready. |
| Text or CSS looks different | html2canvas does not support the CSS feature exactly as the browser does | Simplify the export CSS, create an export-only layout, or switch to PDF-native components. |
| Characters become boxes or disappear | The selected PDF font lacks required glyphs | Embed a custom TTF with coverage for the report’s scripts and test the actual output. |
| Pages split awkwardly | Complex flex/grid, fixed heights, or oversized blocks | Remove rigid heights, break content into smaller sections, adjust margins, and test autoPaging in target browsers. |
| Server rendering throws DOM errors | The html2canvas path is being run without a browser | Move conversion to a browser interaction or adopt a renderer designed for the server environment. |
| Export includes buttons or menus | The ref wraps application chrome | Move the ref to a document-only wrapper or render a dedicated export component. |
Test checklist before shipping
- Open the export in each supported browser and inspect every page.
- Test short, very long, and empty datasets.
- Test remote images, custom fonts, accented text, and non-Latin scripts.
- Check landscape output for wide tables and verify margins on paper-sized pages.
- Capture the component only after data, images, and fonts are ready.
- Try user-controlled text and URLs to confirm sanitization and safe resource handling.
- Decide whether a dedicated PDF-native layout is preferable for a designed document.
Or skip the browser setup
If the React report is available at a public or authenticated URL, ScreenshotNeo can capture the rendered page without you maintaining browser automation. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the result with X-Page-Verdict and X-Billed headers.
For an HTTP request, the documented call is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://your-site.example/report -o report.webp
See the ScreenshotNeo documentation for the current request and PDF options. The same service offers an MCP server for Claude, Cursor, and other MCP clients, with take_screenshot, get_page_info, and capture_pdf tools. PDF captures can specify paper size, margins, landscape mode, and page ranges.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallEquivalent client calls are:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://your-site.example/report"}, timeout=90)
r.raise_for_status()
open("report.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://your-site.example/report' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo request failed: ${res.status}`);
It also supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets plus custom viewports, retina scale, custom CSS and JavaScript, clicks before capture, selector waits or delays, network-idle waits, ad/tracker/request blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, an OpenAPI specification, and familiar parameter names for easier migration.
The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is included on every plan. Create a free ScreenshotNeo account to try it.
Frequently Asked Questions
Can I export only one nested element instead of the whole component?
Yes. Attach the React ref directly to the nested section you want to convert, and keep unrelated controls outside that element.
Does jsPDF automatically preserve my site’s web fonts?
No. Verify glyph coverage and embed a suitable custom TTF when the report contains characters outside the limited ASCII range of the standard PDF fonts.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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.

