[reactjs] Generating a PDF file from React Components

I have been building a polling application. People are able to create their polls and get data regarding the question(s) they ask. I would like to add the functionality to let the users download the results in the form of a PDF.

For example I have two components which are responsible for grabbing the question and data.

<QuestionBox />
<ViewCharts />

I'm attempting to output both components into a PDF file. The user can then download this PFD file. I have found a few packages that permit the rendering of a PDF inside a component. However I failed to find one that can generate PDF from an input stream consisting of a virtual DOM. If I want to achieve this from scratch what approach should I follow ?

This question is related to reactjs pdf meteor

The answer is


I used jsPDF and html-to-image.

You can check out the code on the below git repo.

Link

If you like, you can drop a star there??


Only few steps. We can download or generate PDF from our HTML page or we can generate PDF of specific div from a HTML page.

Steps : HTML -> Image (PNG or JPEG) -> PDF

Please Follow the below steps,

Step 1 :-

npm install --save html-to-image
npm install jspdf --save

Step 2 :-

/* ES6 */
import * as htmlToImage from 'html-to-image';
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from 'html-to-image';
 
/* ES5 */
var htmlToImage = require('html-to-image');

-------------------------
import { jsPDF } from "jspdf";

Step 3 :-

   ******  With out PDF properties given below  ******

 htmlToImage.toPng(document.getElementById('myPage'), { quality: 0.95 })
        .then(function (dataUrl) {
          var link = document.createElement('a');
          link.download = 'my-image-name.jpeg';
          const pdf = new jsPDF();          
          pdf.addImage(dataUrl, 'PNG', 0, 0);
          pdf.save("download.pdf"); 
        });


    ******  With PDF properties given below ******

    htmlToImage.toPng(document.getElementById('myPage'), { quality: 0.95 })
        .then(function (dataUrl) {
          var link = document.createElement('a');
          link.download = 'my-image-name.jpeg';
          const pdf = new jsPDF();
          const imgProps= pdf.getImageProperties(dataUrl);
          const pdfWidth = pdf.internal.pageSize.getWidth();
          const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
          pdf.addImage(dataUrl, 'PNG', 0, 0,pdfWidth, pdfHeight);
          pdf.save("download.pdf"); 
        });

I think this is helpful. Please try


You can use ReactPDF

Lets you convert a div into PDF with ease. You will need to match your existing markup to use ReactPDF markup, but it is worth it.


This may or may not be a sub-optimal way of doing things, but the simplest solution to the multi-page problem I found was to ensure all rendering is done before calling the jsPDFObj.save method.

As for rendering hidden articles, this is solved with a similar fix to css image text replacement, I position absolutely the element to be rendered -9999px off the page left, this doesn't affect layout and allows for the elem to be visible to html2pdf, especially when using tabs, accordions and other UI components that depend on {display: none}.

This method wraps the prerequisites in a promise and calls pdf.save() in the finally() method. I cannot be sure that this is foolproof, or an anti-pattern, but it would seem that it works in most cases I have thrown at it.

_x000D_
_x000D_
// Get List of paged elements._x000D_
let elems = document.querySelectorAll('.elemClass');_x000D_
let pdf = new jsPDF("portrait", "mm", "a4");_x000D_
_x000D_
// Fix Graphics Output by scaling PDF and html2canvas output to 2_x000D_
pdf.scaleFactor = 2;_x000D_
_x000D_
// Create a new promise with the loop body_x000D_
let addPages = new Promise((resolve,reject)=>{_x000D_
  elems.forEach((elem, idx) => {_x000D_
    // Scaling fix set scale to 2_x000D_
    html2canvas(elem, {scale: "2"})_x000D_
      .then(canvas =>{_x000D_
        if(idx < elems.length - 1){_x000D_
          pdf.addImage(canvas.toDataURL("image/png"), 0, 0, 210, 297);_x000D_
          pdf.addPage();_x000D_
        } else {_x000D_
          pdf.addImage(canvas.toDataURL("image/png"), 0, 0, 210, 297);_x000D_
          console.log("Reached last page, completing");_x000D_
        }_x000D_
  })_x000D_
  _x000D_
  setTimeout(resolve, 100, "Timeout adding page #" + idx);_x000D_
})_x000D_
_x000D_
addPages.finally(()=>{_x000D_
   console.log("Saving PDF");_x000D_
   pdf.save();_x000D_
});
_x000D_
_x000D_
_x000D_


React-PDF is a great resource for this.

It is a bit time consuming converting your markup and CSS to React-PDF's format, but it is easy to understand. Exporting a PDF and from it is fairly straightforward.

To allow a user to download a PDF generated by react-PDF, use their on the fly rendering, which provides a customizable download link. When clicked, the site renders and downloads the PDF for the user.

Here's their REPL which will familiarize you with the markup and styling required. They have a download link for the PDF too, but they don't show the code for that here.


You can use ReactDOMServer to render your component to HTML and then use this on jsPDF.

First do the imports:

import React from "react";
import ReactDOMServer from "react-dom/server";
import jsPDF from 'jspdf';

then:

var doc = new jsPDF();
doc.fromHTML(ReactDOMServer.renderToStaticMarkup(this.render()));
doc.save("myDocument.pdf");

Prefer to use:

renderToStaticMarkup

instead of:

renderToString

As the former include HTML code that react relies on.


npm install jspdf --save

//code on react

import jsPDF from 'jspdf';


var doc = new jsPDF()


 doc.fromHTML("<div>JOmin</div>", 1, 1)


onclick //

 doc.save("name.pdf")

you can user canvans with jsPDF

import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';

 _exportPdf = () => {

     html2canvas(document.querySelector("#capture")).then(canvas => {
        document.body.appendChild(canvas);  // if you want see your screenshot in body.
        const imgData = canvas.toDataURL('image/png');
        const pdf = new jsPDF();
        pdf.addImage(imgData, 'PNG', 0, 0);
        pdf.save("download.pdf"); 
    });

 }

and you div with id capture is:

example

<div id="capture">
  <p>Hello in my life</p>
  <span>How can hellp you</span>
</div>

Examples related to reactjs

Error: Node Sass version 5.0.0 is incompatible with ^4.0.0 TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type undefined raised when starting react app Template not provided using create-react-app How to resolve the error on 'react-native start' Element implicitly has an 'any' type because expression of type 'string' can't be used to index Invalid hook call. Hooks can only be called inside of the body of a function component How to style components using makeStyles and still have lifecycle methods in Material UI? React Hook "useState" is called in function "app" which is neither a React function component or a custom React Hook function How to fix missing dependency warning when using useEffect React Hook? Unable to load script.Make sure you are either running a Metro server or that your bundle 'index.android.bundle' is packaged correctly for release

Examples related to pdf

ImageMagick security policy 'PDF' blocking conversion How to extract table as text from the PDF using Python? Extract a page from a pdf as a jpeg How can I read pdf in python? Generating a PDF file from React Components Extract Data from PDF and Add to Worksheet How to extract text from a PDF file? How to download PDF automatically using js? Download pdf file using jquery ajax Generate PDF from HTML using pdfMake in Angularjs

Examples related to meteor

Hide Signs that Meteor.js was Used Generating a PDF file from React Components Console logging for react? Facebook login message: "URL Blocked: This redirect failed because the redirect URI is not whitelisted in the app’s Client OAuth Settings." "continue" in cursor.forEach() node.js vs. meteor.js what's the difference?