
Create dynamic PDFs using React and Node.js
- Transfer
The material, the translation of which we publish today, is devoted to the creation of dynamic PDF-files using HTML-code as a template. Namely, we will talk about how to create a simple invoice for payment of certain goods or services, the dynamic data included in which are taken from the state of the React application. The base of the React application was created using create-react-app, the server part of the project is based on Node.js, and the Express framework was used in its development.
The author of this material notes that he prepared a video that demonstrates the development of the project. If you decide to watch the video and read the article, it is recommended to do so. First, skim through the article, then turn on the video and recreate the system you are considering there. After that, just read the article.

Create a project directory and go to it:
Create a new React application:
After completing the application creation, go to the directory you just created and install the dependencies:
Create an Express server. To do this, create a folder in the project directory
Here, to form
Now, in the file
This will help in working with the local server from the client code.
Now you need to open two windows of the terminal.
In the first window, go to the directory
In the second window, go to the folder
The client part of our project will look very simple.
To begin with, in the file of the
After that, at the top of the component description, initialize the state:
Let's remove the standard JSX markup created in the application template by means
Create a method
Now we can move on to the task of creating a PDF file. That part of it, which is solved by means of the client, is to create a POST request to the server. The request sends the application state:
Before we continue working on the client side of the project, we need to configure the routes on the server. This will allow the server to receive data from the client, generate a PDF file and transfer this file back to the client.
The server part of the project will include only two routes. One is needed to create PDFs. The second is for sending files to the client.
First, import the
We initialize the Express application and configure the port:
Set up the query parser. What we need will be available as
After that, start the server:
Now we can tackle the code responsible for creating the PDFs.
We need an HTML template to use when creating PDF files. In creating such a template, endless possibilities open up before us. Everything that can be created using pure HTML and CSS can be represented as a PDF file. Create a folder in the
From this file, we export an arrow function that will return all the necessary HTML code. When calling this function, you can use the parameters, which we will also describe here.
Here I will give you an example of an HTML template, and you just copy it into your project. But you, of course, can create your own template.
Let's bring the code
Include this file in the file
Recall that on the server we are going to create two routes. The POST route will be responsible for receiving data from the client and creating a PDF file. The GET route will be used to send the finished file to the client.
In the POST route,
The
In order to return
At the same time, we will create a route that will be used after, at the request of the client, a PDF file is successfully created. Here we just take the finished document and send it to the client using
Now we can return to the client code and continue working on the function
If after executing a POST request to the server a PDF document was created, we need to execute a GET request, in response to which the server will send the finished document to the client.
To implement this pattern of behavior, we, after a call
We supplement the function with the following code:
Here you can pay attention to what is
Blob is an immutable object representing some raw data. Such objects are often used to work with data that may not be in native JavaScript format. Such objects are sequences of bytes that store, for example, file data. It may seem that the object
Now that we know what the objects are
This is what the browser interface looks like.

Application in the browser
After filling in the fields and clicking on the button

Download a PDF document
And here is the PDF document itself.

Software Generated PDF
We looked at a mechanism that allows you to programmatically create PDF files. Here is a GitHub repository with project code. We hope that the ideas that you met in this material will find application in your development.
Dear readers! How would you go about solving the problem of programmatically creating PDF files using Node.js?

Project creation
Create a project directory and go to it:
mkdir pdfGenerator && cd pdfGenerator
Create a new React application:
create-react-app client
After completing the application creation, go to the directory you just created and install the dependencies:
cd client && npm i -S axios file-saver
Create an Express server. To do this, create a folder in the project directory
server
and go to it. In it, create a file index.js
and run the initialization of the project:mkdir server && cd server && touch index.js && npm init
Here, to form
package.json
, just click on several times Enter
. After that, execute the following command to add the necessary dependencies to the server part of the project:npm i -S express body-parser cors html-pdf
Now, in the file
client/package.json
, above the dependency description section, add the following:"proxy": "http://localhost:5000/"
This will help in working with the local server from the client code.
Now you need to open two windows of the terminal.
In the first window, go to the directory
client
and execute the following command:npm start
In the second window, go to the folder
server
and execute the following command:nodemon index.js
Initial client setup
The client part of our project will look very simple.
To begin with, in the file of the
src/App.js
client part of the application, we import into the dependency code:import axios from 'axios';
import { saveAs } from 'file-saver';
After that, at the top of the component description, initialize the state:
state = {
name: 'Adrian',
receiptId: 0,
price1: 0,
price2: 0,
}
Let's remove the standard JSX markup created in the application template by means
create-react-app
and returned from the method render()
. Insert the following into it:
Create a method
handleChange
that will be responsible for updating the application state data related to the input fields:handleChange = ({ target: { value, name }}) => this.setState({ [name]: value })
Now we can move on to the task of creating a PDF file. That part of it, which is solved by means of the client, is to create a POST request to the server. The request sends the application state:
createAndDownloadPdf = () => {
axios.post('/create-pdf',
this.state)
}
Before we continue working on the client side of the project, we need to configure the routes on the server. This will allow the server to receive data from the client, generate a PDF file and transfer this file back to the client.
Initial server setup
The server part of the project will include only two routes. One is needed to create PDFs. The second is for sending files to the client.
First, import the
index.js
dependencies into the file :const express = require('express');
const bodyParser = require('body-parser');
const pdf = require('html-pdf');
const cors = require('cors');
We initialize the Express application and configure the port:
const app = express();
const port = process.env.PORT || 5000;
Set up the query parser. What we need will be available as
req.body
. We will also configure CORS so that our work would not be prevented by an error Cross-Origin Request Blocked
:app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
After that, start the server:
app.listen(port, () => console.log(`Listening on port ${port}`));
Now we can tackle the code responsible for creating the PDFs.
Create an HTML template for PDFs
We need an HTML template to use when creating PDF files. In creating such a template, endless possibilities open up before us. Everything that can be created using pure HTML and CSS can be represented as a PDF file. Create a folder in the
server
directory documents
, let's move in it and create a file in it index.js
:mkdir documents && cd documents && touch index.js
From this file, we export an arrow function that will return all the necessary HTML code. When calling this function, you can use the parameters, which we will also describe here.
module.exports = ({ name, price1, price2, receiptId }) => { ... }
Here I will give you an example of an HTML template, and you just copy it into your project. But you, of course, can create your own template.
Let's bring the code
index.js
from the folder server/documents
to the following form:module.exports = ({ name, price1, price2, receiptId }) => {
const today = new Date();
return `
PDF Result Template

Datum: ${`${today.getDate()}. ${today.getMonth() + 1}. ${today.getFullYear()}.`}
Customer name: ${name}
Receipt number: ${receiptId}
Bought items: Price First item: ${price1}$ Second item: ${price2}$
Total price: ${parseInt(price1) + parseInt(price2)}$
`;
};
Include this file in the file
server/index.js
:const pdfTemplate = require('./documents');
Create PDFs
Recall that on the server we are going to create two routes. The POST route will be responsible for receiving data from the client and creating a PDF file. The GET route will be used to send the finished file to the client.
▍ create-pdf route
In the POST route,
create-pdf
we will use the command pdf.create()
, referring to the object imported from the module html-pdf
. The
pdf.create()
HTML template is used as the first parameter of the method , as well as data received from the client. In order to return
pdf.create()
, we will call the method toFile()
, passing it the name that we want to assign to the PDF document, as well as the arrow callback function. This function, in case of an error, will execute the command res.send(Promise.reject())
. In the event that everything went well, she will execute the command res.send(Promise.resolve())
.app.post('/create-pdf', (req, res) => {
pdf.create(pdfTemplate(req.body), {}).toFile('result.pdf', (err) => {
if(err) {
res.send(Promise.reject());
}
res.send(Promise.resolve());
});
});
▍Fetch-pdf Route
At the same time, we will create a route that will be used after, at the request of the client, a PDF file is successfully created. Here we just take the finished document and send it to the client using
res.sendFile()
:app.get('/fetch-pdf', (req, res) => {
res.sendFile(`${__dirname}/result.pdf`)
})
Client function createAndDownloadPdf
Now we can return to the client code and continue working on the function
createAndDownloadPdf
. Here we execute a POST request to the server using the module axios
. Now this function looks like this:createAndDownloadPdf = () => {
axios.post('/create-pdf',
this.state)
}
If after executing a POST request to the server a PDF document was created, we need to execute a GET request, in response to which the server will send the finished document to the client.
To implement this pattern of behavior, we, after a call
axios.post()
, call. then()
. This allows us to do that in response to the client’s POST request, we return a promise from the server that can be either successfully resolved or rejected. We supplement the function with the following code:
.then(() => axios.get('/fetch-pdf', { responseType: 'blob' }))
.then((
res) => {})
Here you can pay attention to what is
responseType
used as quality blob
. Before we go any further, let's talk about what it is.Blob objects
Blob is an immutable object representing some raw data. Such objects are often used to work with data that may not be in native JavaScript format. Such objects are sequences of bytes that store, for example, file data. It may seem that the object
Blob
stores a link to a file, but in fact it is not. These objects store data that you can work with. For example - they can be saved to files.Project Completion
Now that we know what the objects are
Blob
, we can take advantage of another challenge .then()
by creating, on the basis of it res.data
, a new Blob
-object. When creating this object, we will pass a parameter to its constructor, indicating that the data that the object will store is of type application/pdf
. After that, we can use the method saveAs()
that was imported from the module file-saver
and save the data to a file. As a result, the method code createAndDowndloadPdf
will look like the one shown below: createAndDownloadPdf = () => {
axios.post('/create-pdf', this.state)
.then(() => axios.get('fetch-pdf', { responseType: 'blob' }))
.then((res) => {
const pdfBlob = new Blob([res.data], { type: 'application/pdf' });
saveAs(pdfBlob, 'newPdf.pdf');
})
}
This is what the browser interface looks like.

Application in the browser
After filling in the fields and clicking on the button
Download PDF
, data is transferred to the server and a PDF document is downloaded from it.
Download a PDF document
And here is the PDF document itself.

Software Generated PDF
Summary
We looked at a mechanism that allows you to programmatically create PDF files. Here is a GitHub repository with project code. We hope that the ideas that you met in this material will find application in your development.
Dear readers! How would you go about solving the problem of programmatically creating PDF files using Node.js?