Creating Dynamic PDFs with JsPDF and Customizing AutoTables in React (2024)

Creating Dynamic PDFs with JsPDF and Customizing AutoTables in React (2)

In this tutorial, we’ll explore how to generate dynamic PDFs in a React application using jsPDF. We’ll focus on enhancing the PDF generation process by customizing AutoTable, implementing dynamic page numbering, and ensuring flexible page allocation.

STEPS:

1. Setup the React App

2. Install jsPDF

3. Install jspdf-autotable

4. Import Required Libraries and Components in App.js file

5. Define the generatePdf Function

6. Render the Main Content Using JSX

7. Create the pdfGenerator file component and Import Necessary Libraries

8. Sample Vendor and Items Data

9. Create a new jsPDF Instance and Set Properties

10. Add Images and Text to the PDF

11. Generate AutoTable for Item Details

12. Save (or) Open the PDF

13. Run the Application

Prerequisites

Before proceeding, check if Node.js and npm are already installed on your machine. Open your terminal and run the following commands.

Step 1: Setup the React App

Open your terminal and run the following commands to create a new React app.

npx create-react-app pdf-generator
cd pdf-generator

Step 2: Install jsPDF

Install the jsPDF library by running:

npm install jspdf

Step 3: Install jspdf-autotable

Install the jspdf-autotable library by running:

npm install jspdf-autotable

Step 4: Import Required Libraries and Components in App.js file

import React from 'react';
import { Button, DownloadIcon } from 'lumina-ui';
import PdfGenerator from './pdfGenerator';

Import the React library for building React components.

Import the Button and DownloadIcon components from the ‘lumina-ui’ library.

Import the PdfGenerator component from a local file named ‘pdfGenerator.js’.

Step 5: Define the generatePdf Function

 const generatePdf = () => {
PdfGenerator();
}

Define a function named generatePdf responsible for triggering the PDF generation when the button is clicked.

Call the PdfGenerator function imported from ‘pdfGenerator.js’.

Step 6: Render the Main Content Using JSX

 return (
<div style={{ justifyContent: "center", display: "flex", alignItems: "center", height: "100vh" }}>
<div>
<p>Click here to download the PDF file.</p>
<div style={{ display: "flex", justifyContent: "center" }}>
<Button
onClick={generatePdf}
icon={<DownloadIcon />}
type="button"
shape="rectangle"
size="small"
>
</Button>
</div>
</div>
</div>)

Use JSX to define the structure of the App component.

Create a div with inline styles that center its content both horizontally and vertically using flexbox.

Include a paragraph (<p>) with the text “Click here to download the PDF file.”

onClick: Specifies the generatePdf function to be executed when the button is clicked.

Step7: Create the pdfGenerator file component and Import Necessary Libraries

import jsPDF from 'jspdf';
import 'jspdf-autotable';
import { format } from 'date-fns';

Here, we import the required libraries: jsPDF for PDF generation, jspdf-autotable for creating tables in the PDF, and format from date-fns for formatting dates.

Step8: Sample Vendor and Items Data

const vendorData = {
// ... (vendor data, see previous code)
}
const itemsData = [
// ... (items data, see previous code)
];

Sample data for the vendor and items. You can replace this with dynamic data from your application.

Step9: Create a new jsPDF Instance and Set Properties

const pdf = new jsPDF();
pdf.setProperties({
title: "Request For Quotation"
});

Initialize a new jsPDF instance and set properties for the PDF, such as the title.

Step10: Add Images and Text to the PDF

pdf.addImage(imageUrl, 'JPEG', 10, 5, 40, 12);

This line of code adds an image to the RFQ PDF at a specific location with a defined size. The image is positioned 10 units from the left and 5 units from the top, and it has a width of 40 units and a height of 12 units.

pdf.setFontSize(10);

This line off code adds a font size.

pdf.setFont('custom', 'bold');

this line off code adds a font weight.

pdf.text('REQUEST FOR QUOTATION', 150, 12);

This line of code adds a title to the RFQ PDF at a specific location. The title is positioned 150 units from the left and 12 units from the top. Adjust these coordinates based on your layout preferences.

Step11: Generate AutoTable for Item Details

pdf.autoTable({
head: [itemDetailsHeaders],
body: itemDetailsRows,
startY: itemDetailsYStart, // Adjust the Y position as needed
headStyles: {
fillColor: headerStyles.fillColor,
textColor: headerStyles.textColor,
fontStyle: headerStyles.fontStyle,
fontSize: 10, // Adjust the font size as needed
font: 'Newsreader', // Set the font family
halign: 'left',
},
columnStyles: {
0: { cellWidth: columnWidths[0] }, // Adjust column widths as needed
1: { cellWidth: columnWidths[1] },
2: { cellWidth: columnWidths[2] },
3: { cellWidth: columnWidths[3] },
4: { cellWidth: columnWidths[4] },
},
alternateRowStyles: { fillColor: [255, 255, 255] },
bodyStyles: {
fontSize: 10, // Adjust the font size for the body
font: 'Newsreader', // Set the font family for the body
cellPadding: { top: 1, right: 5, bottom: 1, left: 2 }, // Adjust cell padding
textColor: [0, 0, 0], // Set text color for the body
rowPageBreak: 'avoid', // Avoid row page breaks
},
margin: { top: 10, left: 13 },
});

pdf.autoTable: This function is provided by the jsPDF-AutoTable library. It automatically generates a table based on the provided data and settings.

head: An array containing the headers of the table. In this case, it’s an array of strings representing the header names.

body: A 2D array containing the rows of the table. Each row is represented by an array of strings or numbers.

startY: The Y-axis position where the table should start. Adjust this based on the layout and positioning in your document.

headStyles: Styles for the table headers, including fill color, text color, font style, font size, font family, and horizontal alignment.

columnStyles: Styles for individual columns, allowing you to set specific widths for each column.

alternateRowStyles: Styles for alternating rows, providing a different fill color for better readability.

bodyStyles: Styles for the body of the table, including font size, font family, cell padding, text color, and avoiding row page breaks.

margin: Sets the top and left margin for the table.

Step12: Dynamic Page calculation and Page Numbers

const summaryYStart = pdf.internal.pageSize.getHeight() - 50;

pdf.internal.pageSize.getHeight(): This part retrieves the height of the current PDF page. The pdf.internal.pageSize object contains information about the dimensions of the page, and getHeight() specifically fetches the height of the page.

const totalPages = pdf.internal.getNumberOfPages();
for (let i = 1; i <= totalPages; i++) {
pdf.line(10, 283, 200, 283);
pdf.setPage(i);
pdf.setFont('Newsreader');
pdf.text(
`Page ${i} of ${totalPages}`,
185,
pdf.internal.pageSize.getHeight() - 5
);
}

const totalPages = pdf.internal.getNumberOfPages();: This line calculates the total number of pages in the generated PDF using the getNumberOfPages() method provided by jsPDF.

for (let i = 1; i <= totalPages; i++) This initiates a loop that iterates through each page of the PDF.

pdf.line(10, 283, 200, 283);: Draws a horizontal line at the bottom of each page. The line starts at coordinates (10, 283) and ends at (200, 283). This line serves as a separator between the content and the page number.

pdf.setPage(i);: Sets the current page to the ith page in the loop, allowing the following operations to be applied to the correct page.

pdf.setFont(‘Newsreader’);: Sets the font for the page number text. In this case, it uses the ‘Newsreader’ font.

pdf.text(Page ${i} of ${totalPages}, 185, pdf.internal.pageSize.getHeight() — 5);: Adds the page number text to the current page. It displays the current page number and the total number of pages at coordinates (185, pdf.internal.pageSize.getHeight() — 5). Adjust the coordinates and text formatting as needed for your layout.

This code ensures that each page of the PDF includes a horizontal line at the bottom and displays the page number and total number of pages in the specified font and position.

Step13: Save (or) Open the PDF

pdf.save(`RFQ.pdf`);

const pdfDataUri = pdf.output('datauristring');
const newTab = window.open();
newTab?.document.write(`<iframe width='100%' height='100%' src='${pdfDataUri}'></iframe>`);

pdf.save(RFQ.pdf): This line of code saves the generated PDF with the filename “RFQ.pdf”. The save method is provided by the jsPDF library and triggers the browser’s download functionality to save the PDF file.

const pdfDataUri = pdf.output(‘datauristring’): The output method with the parameter ‘datauristring’ is used to obtain the data URI of the generated PDF. A data URI is a base64-encoded representation of the file, allowing it to be embedded directly into the HTML.

const newTab = window.open(): This code opens a new browser tab using the window.open() method. This new tab will be used to display the preview of the generated PDF.

newTab?.document.write(<iframe width=’100%’ height=’100%’ src=’${pdfDataUri}’></iframe>): The document.write method is used to write an HTML iframe element into the new tab’s document. The iframe is set to display the PDF using its data URI as the source (src).

Step 14: Run the Application

npm start

This command will start your application. Once the application is running, open your web browser and go to the specified localhost address (usually http://localhost:3000). You should be able to see your application running like this.

Creating Dynamic PDFs with JsPDF and Customizing AutoTables in React (3)

To download the PDF, click on the download button, and the browser will prompt you to save the file with the filename “RFQ.pdf”.

This step-by-step breakdown helps understand how the PdfGenerator component creates a detailed RFQ PDF document.

Below is the sample code for App.js:

import React from 'react';
import { Button, DownloadIcon } from 'lumina-ui';
import PdfGenerator from './pdfGenerator';

const App = () => {

// Function to generate PDF when the button is clicked
const generatePdf = () => {
PdfGenerator();
}

// Render the main content
return (
<div style={{ justifyContent: "center", display: "flex", alignItems: "center", height: "100vh" }}>
<div>
<p>Click here to download the PDF file.</p>
<div style={{display:"flex",justifyContent:"center"}}>
<Button
onClick={generatePdf}
icon={<DownloadIcon />}
type="button"
shape="rectangle"
size="small"
>
</Button>
</div>
</div>
</div>
)
}

export default App

Below is the sample code for pdfGenerator.js:

import React from 'react';
import { Button, DownloadIcon } from 'lumina-ui';
import PdfGenerator from './pdfGenerator';

const App = () => {

// Function to generate PDF when the button is clicked
const generatePdf = () => {
PdfGenerator();
}

// Render the main content
return (
<div style={{ justifyContent: "center", display: "flex", alignItems: "center", height: "100vh" }}>
<div>
<p>Click here to download the PDF file.</p>
<div style={{display:"flex",justifyContent:"center"}}>
<Button
onClick={generatePdf}
icon={<DownloadIcon />}
type="button"
shape="rectangle"
size="small"
>
</Button>
</div>
</div>
</div>
)
}

export default App

Below is the sample code for pdfGenerator.js:
import jsPDF from 'jspdf';
import 'jspdf-autotable';
import { format } from 'date-fns';

// Define the PdfGenerator component
const PdfGenerator = () => {

// Sample vendor data
const vendorData = {
vendorName: "Velavan B",
vendorAddress: "14/203, Kallakulam, Seenapuram",
vendorPinCode: "638057",
contactPerson: "Santhosh D",
contactPersonMobNo: "8993298712",
}

// Sample items data
const itemsData = [
{ itemName: 'Water Tanks', quantity: "15", uom: "Liters", unitPrice: "1200", total: (15 * 1200).toString() },
{ itemName: 'Laptops', quantity: "5", uom: "Pieces", unitPrice: "25000", total: (5 * 25000).toString() },
{ itemName: 'Coffee Mugs', quantity: "50", uom: "Pieces", unitPrice: "50", total: (50 * 50).toString() },
{ itemName: 'Desk Chairs', quantity: "8", uom: "Pieces", unitPrice: "8000", total: (8 * 8000).toString() },
{ itemName: 'LED TVs', quantity: "3", uom: "Units", unitPrice: "30000", total: (3 * 30000).toString() },
{ itemName: 'Bookshelves', quantity: "2", uom: "Units", unitPrice: "5000", total: (2 * 5000).toString() },
{ itemName: 'Smartphones', quantity: "10", uom: "Pieces", unitPrice: "15000", total: (10 * 15000).toString() },
{ itemName: 'Desk Lamps', quantity: "20", uom: "Pieces", unitPrice: "100", total: (20 * 100).toString() },
{ itemName: 'Headphones', quantity: "25", uom: "Pairs", unitPrice: "500", total: (25 * 500).toString() },
{ itemName: 'Backpacks', quantity: "12", uom: "Pieces", unitPrice: "800", total: (12 * 800).toString() },
{ itemName: 'Fitness Trackers', quantity: "7", uom: "Pieces", unitPrice: "1200", total: (7 * 1200).toString() },
{ itemName: 'Digital Cameras', quantity: "4", uom: "Units", unitPrice: "15000", total: (4 * 15000).toString() },
{ itemName: 'Portable Speakers', quantity: "18", uom: "Pieces", unitPrice: "800", total: (18 * 800).toString() },
{ itemName: 'Sunglasses', quantity: "30", uom: "Pairs", unitPrice: "200", total: (30 * 200).toString() },
{ itemName: 'Running Shoes', quantity: "15", uom: "Pairs", unitPrice: "1000", total: (15 * 1000).toString() },
{ itemName: 'Gaming Consoles', quantity: "6", uom: "Units", unitPrice: "25000", total: (6 * 25000).toString() },
{ itemName: 'Wristwatches', quantity: "9", uom: "Pieces", unitPrice: "3000", total: (9 * 3000).toString() },
{ itemName: 'Power Banks', quantity: "20", uom: "Pieces", unitPrice: "500", total: (20 * 500).toString() },
{ itemName: 'Bluetooth Earbuds', quantity: "22", uom: "Pairs", unitPrice: "1000", total: (22 * 1000).toString() },
{ itemName: 'Home Printers', quantity: "3", uom: "Units", unitPrice: "8000", total: (3 * 8000).toString() },
];

// Create a new jsPDF instance
const pdf = new jsPDF();

// Set document properties
pdf.setProperties({
title: "Request For Quotation"
})

// Add images and text to the PDF
const callImage = "/Calling.png";
const imageUrl = "/aalam.png";
pdf.addImage(imageUrl, 'JPEG', 10, 5, 40, 12);
pdf.setFontSize(10);
pdf.setFont('custom', 'bold');
pdf.text('REQUEST FOR QUOTATION', 150, 12);

// Line width in units (you can adjust this)
pdf.setLineWidth(0.1);

// Line color (RGB)
pdf.setDrawColor(200, 200, 200);
pdf.line(10, 18, 200, 18)
pdf.text('Contact Person', 13, 23)
pdf.setFont('custom', 'normal');
pdf.text("Nithish Kumar CP", 13, 28)
pdf.addImage(callImage, 'PNG', 13, 29, 3, 3);
pdf.text("9078382732", 16, 32)
pdf.setFont('Newsreader', 'bold')
pdf.text('RFQ No :', 130, 23)
pdf.text('RFQ Date :', 130, 27)
pdf.text('Due Date :', 130, 31)
pdf.setFont('Newsreader', 'normal')
pdf.text("RFQ20240092", 155, 23)
pdf.text(format(new Date(), 'MMM dd, yyyy'), 155, 27)
pdf.text(format(new Date("2024-02-08 00:00:00.000 +0530"), 'MMM dd, yyyy'), 155, 31)
pdf.line(10, 34, 200, 34)
pdf.setFont('Newsreader', 'bold')
pdf.text('To', 13, 39)
pdf.setFont('Newsreader', 'bold')
pdf.text('Purchase Centre Address :', 130, 39)
pdf.setFont('Newsreader', 'normal')
pdf.text('Head Office', 130, 44)
pdf.text('CHENNAI', 130, 48)

// Generate the vendor-specific content
pdf.setFont('Newsreader', 'bold');
pdf.text(`${vendorData?.vendorName}`, 13, 44);
pdf.text(`${vendorData?.vendorAddress}`, 13, 48)
pdf.setFont('Newsreader', 'normal');
pdf.text(`P.O BOX : ${vendorData?.vendorPinCode}`, 13, 52);
pdf.setFont('Newsreader', 'bold')
pdf.text('Contact Person', 13, 56)
pdf.setFont('Newsreader', 'normal')
pdf.text(`${vendorData?.contactPerson}`, 13, 60);
pdf.addImage(callImage, 'PNG', 13, 61, 3, 3);
pdf.text(` ${vendorData?.contactPersonMobNo || "N/A"}`, 16, 64);
pdf.setFont('Newsreader', 'bold')
pdf.text('Dear Sir,', 13, 72)
pdf.setFont('Newsreader', 'normal')
pdf.text('Please send your most competitive offer/mentioning your Terms & Conditions before the due date. You can send the same to \nthe above mentioned e-mail/fax', 13, 79)
pdf.setFont('Newsreader', 'normal')
pdf.setFontSize(10);

// Generate AutoTable for item details
const itemDetailsRows = itemsData?.map((item, index) => [
(index + 1).toString(),
item.itemName.toString(),
item.quantity?.toString(),
item.uom?.toString(),
item.total?.toLocaleString(),
]);
const itemDetailsHeaders = ['S.No', 'Item Name', 'Quantity', 'UOM', 'Total'];
const columnWidths = [15, 90, 30, 30, 23]; // Adjust column widths as needed
// Define table styles
const headerStyles = {
fillColor: [240, 240, 240],
textColor: [0],
fontFamily: 'Newsreader',
fontStyle: 'bold',
};

pdf.setFont('Newsreader');
const itemDetailsYStart = 88;
pdf.autoTable({
head: [itemDetailsHeaders],
body: itemDetailsRows,
startY: itemDetailsYStart, // Adjust the Y position as needed
headStyles: {
fillColor: headerStyles.fillColor,
textColor: headerStyles.textColor,
fontStyle: headerStyles.fontStyle,
fontSize: 10, // Adjust the font size as needed
font: 'Newsreader', // Set the font family
halign: 'left',
},
columnStyles: {
0: { cellWidth: columnWidths[0] }, // Adjust column widths as needed
1: { cellWidth: columnWidths[1] },
2: { cellWidth: columnWidths[2] },
3: { cellWidth: columnWidths[3] },
4: { cellWidth: columnWidths[4] },
},
alternateRowStyles: { fillColor: [255, 255, 255] },
bodyStyles: {
fontSize: 10, // Adjust the font size for the body
font: 'Newsreader', // Set the font family for the body
cellPadding: { top: 1, right: 5, bottom: 1, left: 2 }, // Adjust cell padding
textColor: [0, 0, 0], // Set text color for the body
rowPageBreak: 'avoid', // Avoid row page breaks
},
margin: { top: 10, left: 13 },
});

// Add summary and page numbers
const summaryYStart = pdf.internal.pageSize.getHeight() - 50;

pdf.setFont('Newsreader', 'noraml')
pdf.text('Thanking You,', 13, summaryYStart + 20)
pdf.text('Yours Faithfully,', 13, summaryYStart + 24)
pdf.text('For ', 13, summaryYStart + 28)
pdf.setFont('Newsreader', 'bold')
pdf.text('Aalam Info Solutions LLP', 19, summaryYStart + 28)

const totalPages = pdf.internal.getNumberOfPages();
for (let i = 1; i <= totalPages; i++) {
pdf.line(10, 283, 200, 283)
pdf.setPage(i);
pdf.setFont('Newsreader');
pdf.text(
`Page ${i} of ${totalPages}`,
185,
pdf.internal.pageSize.getHeight() - 5
);
}

// Save the PDF
pdf.save(`RFQ.pdf`);

// pdf open in a new tab
const pdfDataUri = pdf.output('datauristring');
const newTab = window.open();
newTab?.document.write(`<iframe width='100%' height='100%' src='${pdfDataUri}'></iframe>`);

}

export default PdfGenerator

Creating Dynamic PDFs with JsPDF and Customizing AutoTables in React (4)

— by Velavan Balaraman

About Us

Established in 2016, with the goal of being the company of right choice for clients, talents and solution providers. We design, develop and integrate software applications to meet the challenges of a dynamic business environment that suits our client’s needs. Today, we are one of the growing software service provider in the industry aimed at providing custom application development and suitable technical solution. Our team aspires to do quality work for our clients in providing end-to-end solutions and services at an affordable price .

Website : https://aalamsoft.com/

Follow us on,

LinkedIn : https://www.linkedin.com/company/aalam-info-solution-llp

Instagram : https://instagram.com/aalaminfo?igshid=YmMyMTA2M2Y=

Facebook : https://www.facebook.com/Aalam-Info-Solutions-LLP-775574966147738/

Creating Dynamic PDFs with JsPDF and Customizing AutoTables in React (2024)
Top Articles
Journal Proper
TurboTax enters adjustment on California return for Treasury interest on wrong line
Ron Martin Realty Cam
Sprinter Tyrone's Unblocked Games
Food King El Paso Ads
Walgreens Pharmqcy
Satyaprem Ki Katha review: Kartik Aaryan, Kiara Advani shine in this pure love story on a sensitive subject
COLA Takes Effect With Sept. 30 Benefit Payment
Free Atm For Emerald Card Near Me
Wild Smile Stapleton
Craigslist Vermillion South Dakota
Mikayla Campinos Videos: A Deep Dive Into The Rising Star
Wordscape 5832
Dallas’ 10 Best Dressed Women Turn Out for Crystal Charity Ball Event at Neiman Marcus
Illinois Gun Shows 2022
Quest: Broken Home | Sal's Realm of RuneScape
kvoa.com | News 4 Tucson
Mals Crazy Crab
Black Panther 2 Showtimes Near Epic Theatres Of Palm Coast
O'reilly's In Mathis Texas
Cfv Mychart
Mjc Financial Aid Phone Number
October 19 Sunset
NIST Special Publication (SP) 800-37 Rev. 2 (Withdrawn), Risk Management Framework for Information Systems and Organizations: A System Life Cycle Approach for Security and Privacy
Fox And Friends Mega Morning Deals July 2022
Dumb Money, la recensione: Paul Dano e quel film biografico sul caso GameStop
O'reilly Auto Parts Ozark Distribution Center Stockton Photos
Texters Wish You Were Here
Movies123.Pick
Samsung 9C8
SOC 100 ONL Syllabus
Soulstone Survivors Igg
Ise-Vm-K9 Eol
Trizzle Aarp
Jason Brewer Leaving Fox 25
Puretalkusa.com/Amac
How to Print Tables in R with Examples Using table()
Lima Crime Stoppers
'Guys, you're just gonna have to deal with it': Ja Rule on women dominating modern rap, the lyrics he's 'ashamed' of, Ashanti, and his long-awaited comeback
Pokemon Reborn Gyms
Chathuram Movie Download
Inducement Small Bribe
Ehome America Coupon Code
Sechrest Davis Funeral Home High Point Nc
How to Install JDownloader 2 on Your Synology NAS
Kjccc Sports
Oakley Rae (Social Media Star) – Bio, Net Worth, Career, Age, Height, And More
Hdmovie2 Sbs
1990 cold case: Who killed Cheryl Henry and Andy Atkinson on Lovers Lane in west Houston?
Lux Funeral New Braunfels
Hsi Delphi Forum
Lsreg Att
Latest Posts
Article information

Author: Carmelo Roob

Last Updated:

Views: 6647

Rating: 4.4 / 5 (65 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Carmelo Roob

Birthday: 1995-01-09

Address: Apt. 915 481 Sipes Cliff, New Gonzalobury, CO 80176

Phone: +6773780339780

Job: Sales Executive

Hobby: Gaming, Jogging, Rugby, Video gaming, Handball, Ice skating, Web surfing

Introduction: My name is Carmelo Roob, I am a modern, handsome, delightful, comfortable, attractive, vast, good person who loves writing and wants to share my knowledge and understanding with you.