Generating Invoices with React-PDF in React.js: A Step-by-Step Guide
Introduction
PDF generation is a crucial feature for many web applications, especially for creating invoices, reports, and other professional documents. In this tutorial, we’ll walk through creating a professional invoice PDF generator using React-pdf and @ag-media/react-pdf-table in a React.js application.
Prerequisites
Before we begin, make sure you have the following installed:
- Node.js
- React.js project
Step 1: Installing Dependencies
First, install the required packages:
npm install @react-pdf/renderer @ag-media/react-pdf-table
Step 2: Preparing the Data
Let’s start by creating a data.ts
file in the components folder to store our invoice data:
export const tableData = [
{
description: "Web Design Service",
quantity: 1,
unitPrice: 1500.0,
total: 1500.0,
},
{
description: "Hosting Setup",
quantity: 1,
unitPrice: 250.0,
total: 250.0,
},
];
export const totalData = [
{
label: "Subtotal",
value: "$1,750.00",
},
{
label: "Tax (10%)",
value: "$175.00",
},
{
label: "Total",
value: "$1,925.00",
},
];
Step 3: Creating PDF Styles
Create a style.ts
file to define the styling for your PDF:
import { StyleSheet } from "@react-pdf/renderer";
export const styles = StyleSheet.create({
page: {
backgroundColor: "#fff",
color: "#262626",
fontFamily: "Helvetica",
fontSize: "12px",
padding: "30px 50px",
},
header: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 20,
},
title: {
fontSize: 24,
},
textBold: {
fontFamily: "Helvetica-Bold",
},
spaceY: {
display: "flex",
flexDirection: "column",
gap: "2px",
},
billTo: {
marginBottom: 10,
},
table: {
width: "100%",
borderColor: "1px solid #f3f4f6",
margin: "20px 0",
},
tableHeader: {
backgroundColor: "#e5e5e5",
},
td: {
padding: 6,
},
totals: {
display: "flex",
alignItems: "flex-end",
},
});
Style Explanation
page
: Sets the overall page background, text color, font, and paddingheader
: Creates a flex row layout for the invoice header- Additional styles define text formatting, spacing, and table appearance
Step 4: Building the Invoice Component
Create an invoice.tsx
file with the PDF generation logic:
import {
Page,
Text,
View,
Document,
PDFViewer,
PDFDownloadLink,
} from "@react-pdf/renderer";
import { styles } from "./style";
import { Table, TD, TH, TR } from "@ag-media/react-pdf-table";
import { tableData, totalData } from "./data";
export default function Invoice2() {
const InvoicePDF = () => (
<Document>
<Page size="A4" style={styles.page}>
<View style={styles.header}>
<View>
<Text style={[styles.title, styles.textBold]}>INVOICE</Text>
<Text>Invoice #INV-2024-001</Text>
</View>
<View style={styles.spaceY}>
<Text style={styles.textBold}>Company Name</Text>
<Text>123 Business Street</Text>
<Text>City, State 12345</Text>
</View>
</View>
<View style={styles.spaceY}>
<Text style={[styles.billTo, styles.textBold]}>Bill To:</Text>
<Text>Client Name</Text>
<Text>Client Address</Text>
<Text>City, State ZIP</Text>
</View>
{/* Render the table */}
<Table style={styles.table}>
<TH style={[styles.tableHeader, styles.textBold]}>
<TD style={styles.td}>Description</TD>
<TD style={styles.td}>Quantity</TD>
<TD style={styles.td}>Unit Price</TD>
<TD style={styles.td}>Total</TD>
</TH>
{tableData.map((item, index) => (
<TR key={index}>
<TD style={styles.td}>{item.description}</TD>
<TD style={styles.td}>{item.quantity}</TD>
<TD style={styles.td}>${item.unitPrice.toFixed(2)}</TD>
<TD style={styles.td}>${item.total.toFixed(2)}</TD>
</TR>
))}
</Table>
<View style={styles.totals}>
<View
style={{
minWidth: "256px",
}}
>
{totalData.map((item) => (
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
marginBottom: "8px",
}}
>
<Text style={item.label === "Total" ? styles.textBold : {}}>
{item.label}
</Text>
<Text style={item.label === "Total" ? styles.textBold : {}}>
{item.value}
</Text>
</View>
))}
</View>
</View>
</Page>
</Document>
);
return (
<div className="max-w-2xl mx-auto my-10">
<div className="w-full h-[500px]">
<PDFViewer width="100%" height="100%">
<InvoicePDF />
</PDFViewer>
</div>
<div className="mt-6 flex justify-center">
<PDFDownloadLink document={<InvoicePDF />} fileName="invoice.pdf">
<button className="flex items-center bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition duration-300">
Download PDF
</button>
</PDFDownloadLink>
</div>
</div>
);
}
Component Breakdown
InvoicePDF()
: Creates the PDF document structurePDFViewer
: Allows real-time preview of the PDFPDFDownloadLink
: Provides a download button for the generated PDF
Prefer video content? Click here.
Happy coding!