npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-easy-pdf

v0.0.8

Published

A React hook for easy PDF generation.

Downloads

30

Readme

react-easy-pdf

npm version

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-pdf microservice
  • 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

  1. Frontend calls useEasyPdf() with HTML content.
  2. The frontend sends it to your own backend API (e.g., /api/generate-pdf).
  3. Your backend injects the API key and forwards it to the react-easy-pdf microservice.
  4. Microservice generates a PDF and sends it back to your backend.
  5. Backend returns the PDF buffer to frontend — ready to download or preview.

Installation

Using npm:

npm install react-easy-pdf

Using yarn:

yarn add react-easy-pdf

Usage 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/register
  • Request 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-data request to the microservice.

Why Use FormData?

The microservice uses multer middleware, which requires:

  • HTML to be uploaded as a text/plain file (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 (ArrayBuffer or application/pdf for 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-data request 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