react-easy-pdf
v0.0.8
Published
A React hook for easy PDF generation.
Downloads
30
Maintainers
Readme
react-easy-pdf
Overview
react-easy-pdf is a developer-friendly, TypeScript-first React hook library that makes PDF generation simple and secure in any frontend project.
It allows you to send HTML content from your React app to your own backend, which then safely forwards it to a PDF generation microservice. This setup keeps your API keys hidden, ensures secure data handling, and gives you full flexibility on how you want to handle the PDF (e.g., download it, preview it).
No complex setup. No need to expose sensitive credentials. Just a clean, plug-and-play solution to generate PDFs — easily and professionally.
What It Does
- Provides a custom React hook:
useEasyPdf() - Lets you send HTML or component-based content from frontend
- Sends the request to your own backend
- Your backend then communicates with the
react-easy-pdfmicroservice - Keeps your API keys and HTML content safe and private
- Returns a PDF buffer that you can use however you like
Why Use It?
- Secure: API keys stay on your server
- Easy to Use: One hook handles everything
- TypeScript Support: Built with TS from the ground up
🔁 How It Works
[ React Frontend ]
|
| (HTML Data + User Action)
v
[ useEasyPdf() Hook ]
|
v
[ Your Backend API Endpoint ]
|
| (Inject API Key + Encrypt HTML)
v
[ PDF Microservice (react-easy-pdf) ]
|
| (PDF Buffer)
v
[ Your Backend ]
|
v
[ Return PDF to Frontend ]Note: All sensitive operations — like API key usage and HTML encryption — happen on your server, not in the browser.
Summary of Flow
- Frontend calls
useEasyPdf()with HTML content. - The frontend sends it to your own backend API (e.g.,
/api/generate-pdf). - Your backend injects the API key and forwards it to the
react-easy-pdfmicroservice. - Microservice generates a PDF and sends it back to your backend.
- Backend returns the PDF buffer to frontend — ready to download or preview.
Installation
Using npm:
npm install react-easy-pdfUsing yarn:
yarn add react-easy-pdfUsage Example
import { useRef } from 'react';
import { useEasyPdf } from 'react-easy-pdf';
function MyComponent() {
// Reference to the content you want to convert into PDF
const mainRef = useRef<HTMLElement>(null);
// Hook setup
const {
generatePdf, // triggers PDF generation
downloadPdf, // downloads the generated PDF
isLoading, // loading state
isError, // error flag
error, // error details
pdfBlob // generated PDF blob
} = useEasyPdf({
ref: mainRef, // HTML content to convert
mode: 'manual', // manual mode gives you full control
fileName: 'sample.pdf', // output file name
serverUrl: 'http://localhost:3000/api/pdf', // your backend endpoint
pageSettings: {
size: 'A4',
margin: { top: '0px', right: '0px', bottom: '0px', left: '0px' },
scale: 1,
},
});
return (
<main>
<section ref={mainRef}>
{/* Your content to export as PDF */}
<h1>Hello PDF</h1>
<p>This section will be included in the PDF.</p>
</section>
<button onClick={generatePdf} disabled={isLoading || !!pdfBlob}>
{isLoading ? 'Generating...' : 'Generate PDF'}
</button>
{isError && <div>Error: {error?.message}</div>}
{pdfBlob && (
<button onClick={downloadPdf}>
Download PDF
</button>
)}
</main>
);
}Options for useEasyPdf Hook
1. Core Options
| Prop | Type | Required | Description |
| ----------- | ------------------------------------- | -------- | ------------------------------------------------------------------------------ |
| ref | React.RefObject<Element \| null> | Yes | Reference to the DOM element you want to convert into PDF. |
| mode | 'manual' \| 'preview' \| 'download' | No | Determines what action to take after PDF is generated. Defaults to 'manual'. |
| fileName | string | No | Name of the output PDF file (used in download or preview). |
| serverUrl | string | Yes | URL of your backend endpoint that communicates with the PDF microservice. |
2. PDF Page Settings
pageSettings is a required object that defines the paper size, margins, and other options.
| Prop | Type | Required | Description |
| ------------------- | ------------------------------------- | -------- | ---------------------------------------------------------------------------------------- |
| size | 'a4' \| 'A4' \| 'letter' (and more) | No | Paper size. Case-insensitive. Default depends on backend. |
| margin | PageMargins | string | No | Page margin as object ({ top, right, bottom, left }) or shorthand string like '1cm'. |
| landscape | boolean | No | Renders the PDF in landscape mode. |
| printBackground | boolean | No | Whether to print CSS background styles. |
| scale | number | No | Scale of the webpage rendering. Ranges from 0.1 to 2. Default is 1. |
| preferCSSPageSize | boolean | No | Uses CSS-defined page size (@page) instead of manual size. |
3. Callback Functions
| Prop | Type | Required | Description |
| ----------- | ------------------------ | -------- | ---------------------------------------------- |
| onSuccess | (blob: Blob) => void | No | Called when PDF is successfully generated. |
| onError | (error: Error) => void | No | Called when an error occurs during generation. |
Return Values from useEasyPdf
These values are returned from the hook to manage and control the PDF generation flow:
| Return Value | Type | Description |
| ------------- | --------------------- | ---------------------------------------------------- |
| generatePdf | () => Promise<void> | Triggers the PDF generation manually. |
| downloadPdf | () => void | Downloads the PDF if a blob is available. |
| previewPdf | () => void | Opens the PDF in a new tab (if a blob is available). |
| pdfBlob | Blob \| null | PDF blob object that can be downloaded or previewed. |
| error | Error \| null | Contains error details if something goes wrong. |
| isLoading | boolean | Indicates whether a PDF is being generated. |
| isError | boolean | Indicates if an error occurred. |
Available Modes
The mode prop controls the automatic behavior after generating the PDF:
| Mode | Description |
| ------------ | ------------------------------------------------------- |
| 'manual' | Full control — you handle download or preview manually. |
| 'preview' | Automatically opens the PDF in a new tab. |
| 'download' | Automatically downloads the PDF file after generation. |
Backend Setup
To use react-easy-pdf securely, developers must set up a backend route that acts as a bridge between their frontend and the PDF generation microservice.
This setup ensures your API keys remain safe, and HTML is properly encrypted before it's sent to the microservice.
1. Register Your PDF Service Account
Before using the microservice, each developer must register:
Endpoint:
POST https://react-easy-pdf-ms.vikramsamak.com/api/v1/users/registerRequest Body (JSON):
{ "email": "[email protected]", "name": "Your Name" }You can register using tools like cURL, Postman, or any HTTP client.
After successful registration, you’ll receive:
- API Key
- Secret Key (used for encryption)
These credentials will be sent to your email.
2. Free vs. Pro Users
- By default, all registered users are free users.
- Free users can make up to 10 PDF generation requests per day.
- To remove limits, you can become a Pro user by donating via the link below.
💡 Support the project and get Pro access: Donate via Ko-fi
After donating, your account will be upgraded automatically.
3. How to Set Up Your Backend
You must create a POST endpoint on your backend to:
- Accept the HTML to be converted.
- Encrypt the HTML using your secret key.
- Send a
multipart/form-datarequest to the microservice.
Why Use FormData?
The microservice uses multer middleware, which requires:
- HTML to be uploaded as a
text/plainfile (not raw string). - Other data like page settings in JSON format.
4. Required Form Data Structure
Here’s what your backend should send to the microservice:
html– A file (text/plain) containing encrypted HTML.pageSettings– A JSON string specifying PDF layout (size, margin, etc.)
Example (Node.js)
import express from "express";
import axios from "axios";
import multer from "multer";
import CryptoJS from "crypto-js";
import FormData from "form-data";
import { config as loadEnv } from "dotenv";
import cors from "cors";
const app = express();
const upload = multer();
app.use(cors());
// Load environment variables
loadEnv();
app.post(
"/api/generate",
upload.single("html"),
async (req, res): Promise<void> => {
const secretKey = process.env.SECRET_KEY as string;
const apiKey = process.env.API_KEY as string;
try {
// 1. Read raw HTML from uploaded file
const rawHtml = req.file?.buffer.toString("utf-8");
if (!rawHtml) {
res.status(400).json({ error: "HTML is missing" });
return;
}
// 2. Encrypt the HTML using AES
const encryptedHtml = CryptoJS.AES.encrypt(rawHtml, secretKey).toString();
// 3. Read pageSettings from body
const pageSettings = JSON.parse(req.body.pageSettings);
// 4. Prepare new FormData to send to microservice
const formData = new FormData();
formData.append("html", Buffer.from(encryptedHtml), {
filename: "encrypted.txt",
contentType: "text/plain",
});
formData.append("pageSettings", JSON.stringify(pageSettings));
// 5. Call microservice
const response = await axios.post(
"https://react-easy-pdf-ms.vikramsamak.com/api/v1/pdf/generate",
formData,
{
headers: {
...formData.getHeaders(),
"x-api-key": apiKey,
},
responseType: "arraybuffer",
}
);
// 6. Return PDF to frontend
res.set("Content-Type", "application/pdf");
res.send(Buffer.from(response.data));
} catch (error: any) {
console.error("Error generating PDF:", error.message);
if (axios.isAxiosError(error)) {
const status = error.response?.status || 500;
const contentType = error.response?.headers["content-type"];
let errorMessage = "Failed to generate PDF";
if (
error.response?.data &&
contentType &&
contentType.includes("application/json")
) {
try {
const decoded = Buffer.from(error.response.data).toString("utf-8");
const parsed = JSON.parse(decoded);
errorMessage = parsed.error || errorMessage;
} catch (parseErr) {
console.warn("Failed to parse error response JSON");
}
}
res.status(status).json({ error: errorMessage });
return;
}
res.status(500).json({ error: error.message || "PDF generation failed" });
}
}
);
app.listen(3000, () => {
console.log("Server is running on port 3000");
});
If you're using Java, Python, C#, or other languages, make sure to:
- Encrypt using AES (compatible with CryptoJS AES format).
- Send the data using
multipart/form-data.
5. Microservice Encryption Logic (for Reference)
This is how the microservice decrypts the HTML:
import CryptoJS from 'crypto-js';
export function decryptHtml(encryptedHtml: string, secretKey: string): string {
const bytes = CryptoJS.AES.decrypt(encryptedHtml, secretKey);
const decryptedHtml = bytes.toString(CryptoJS.enc.Utf8);
if (!decryptedHtml) {
throw new Error("Failed to decrypt HTML. Possibly invalid key or data.");
}
return decryptedHtml;
}Ensure the encryption on your backend produces data compatible with this decryption logic.
6. Handling Responses and Errors
- On success, the microservice returns a PDF buffer.
- On error, it returns a JSON response like:
{
"error": "Detailed error message here"
}Make sure your backend:
- Checks the response type (
ArrayBufferorapplication/pdffor success). - Handles errors based on the returned JSON.
7. What Happens Inside useEasyPdf()
The hook in your frontend already sends data to your backend using FormData:
formData.append('html', new Blob([html], { type: 'text/plain' }));
formData.append('pageSettings', JSON.stringify({ ...pageSettings, size: pageSettings.size?.toLowerCase() }));So your backend must:
- Receive this form data.
- Encrypt the HTML string.
- Forward it as a new
multipart/form-datarequest to the microservice (along with x-api-key header).
8. Expected Error Format from Your Backend
The react-easy-pdf library expects your backend to return errors in the following format:
{
"error": "Something went wrong."
}Internally, the hook uses Axios like this:
if (axios.isAxiosError(err)) {
const error = err as AxiosError<{ error: string }>;
throw new Error(error.response?.data?.error || 'Failed to generate PDF from server.');
}📬 Contact
For any queries, issues, or support, feel free to reach out to me at [email protected].
👤 Credits
Developed by Vikram Samak
