Generating Invoices with React-PDF in React.js: A Step-by-Step Guide

Candra Kriswinarto
3 min readDec 18, 2024

--

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 padding
  • header: 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 structure
  • PDFViewer: Allows real-time preview of the PDF
  • PDFDownloadLink: Provides a download button for the generated PDF

Prefer video content? Click here.

Happy coding!

--

--

Candra Kriswinarto
Candra Kriswinarto

Written by Candra Kriswinarto

👋 Front-End Developer & YouTuber. I write about web dev, share coding tips, and create tutorials to help others learn. https://youtube.com/@CandDev

No responses yet