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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@spexzee/react-pdfhook

v1.2.1

Published

React hook for generating PDF documents from components

Readme

React PDF Generator Hook - @spexzee/react-pdfhook

npm license downloads types

A production-ready React hook for generating high-fidelity PDFs with advanced layout control and content targeting.

Main Issue solved : if data doesn't fit in a remaining screen it will start from next page

Features

  • Precision PDF Generation

    • Convert React components to pixel-perfect PDFs
    • Support for all HTML/CSS that html2canvas can render
    • Automatic and manual page break controls
  • Advanced Content Targeting

    • Flexible selector system for specific elements
    • PDF-only content visibility (show in PDF but hide in browser)
    • Image handling with CORS support
  • Layout Control

    • Fixed-width mode for consistent cross-device rendering
    • Responsive design preservation
    • Customizable margins and page formats

Installation

npm install @spexzee/react-pdfhook 
# or
yarn add @spexzee/react-pdfhook 

Basic Usage

import { usePdfGenerator } from '@spexzee/react-pdfhook';
import Image from './images/header.jpg'

function DocumentGenerator() {
  const { generatePdf, pdfRef } = usePdfGenerator({
    fileName: 'document.pdf'
  });

  const handleDownload = async () => {
  // manually add which elements we wants in pdf 
  await generatePdf([
    {
      selector: Image.src,
      mapping: false,
      type: 'image',
      imageOptions: {
        width: 180, // mm
        maintainAspectRatio: true
      }
    },
    { 
      selector: '.header-content', 
      mapping: false,
      type: 'element' 
    },
    { 
      selector: '.multi-data', 
      // advantage of using mapping , it will single single data into pdf , so we can easilt manage page-breaks , 

      // if data doesn't fit in a remaining screen it will start from next page
      mapping: true, 
      type: 'element' 
    }
  ]);

};

  return (
    <div>
      <button onClick={handleDownload}>Generate PDF</button>
      <div ref={pdfRef}>
        <div className="header-content">
            <h1>My Document</h1>
            <p>This content will appear in the PDF</p> 
        </div>
        {
            data.map((x)=>(
                <div className="multi-data"> 
                    <AnyComponentName data={x}>
                </div>
            ))
        }
      </div>
    </div>
  );
}

Normal Function example

Component Implementation

import React, { useRef } from 'react';
import { usePdfGenerator } from '@spexzee/react-pdfhook';

const SimplePdfExport = () => {
  const { exportToPdf, pdfRef, pdfLoading } = usePdfGenerator({
    fileName: 'my-document',
  });

  return (
    <div>
      <button onClick={exportToPdf} disabled={pdfLoading}>
        {pdfLoading ? 'Generating...' : 'Export PDF'}
      </button>

      {/* This div's contents will be converted to PDF */}
      <div ref={pdfRef} style={{ padding: '20px' }}>
        <h1>Document Title</h1>
        
        <div className="section">
          <h2>Section 1</h2>
          <p>This content will be processed (parent element)</p>
          
          <div className="subsection">
            <p>Nested content 1 (child element)</p>
            <p>Nested content 2 (child element)</p>
          </div>
        </div>
        
        <div className="footer">
          <p>This footer has no children and will be processed directly</p>
        </div>
      </div>
    </div>
  );
};

export default SimplePdfExport;

2. PDF-Only Content

<div ref={pdfRef}>
  {/* Visible in both browser and PDF */}
  <h1>Public Report</h1>
  
  {/* Hidden in browser, visible only in PDF */}
  <div className="pdf-only">
    <h2>Confidential Details</h2>
    <p>Only visible in the generated PDF</p>
  </div>
</div>

2. Screen-Only Content

<div ref={pdfRef}>
  {/* Visible in both browser and PDF */}
  <h1>Public Report</h1>
  
  {/* Hidden in pdf, visible only in browser */}
  <div className="screen-only">
    <h2>Confidential Details</h2>
    <p>Only visible in the generated PDF</p>
  </div>
</div>

Required CSS for PDF Only:

.pdf-only {
  display: none;
}

@media print {
  .pdf-only {
    display: block;
  }
}

3. Layout Control

const { generatePdf } = usePdfGenerator({
  fixedWidth: 1200, // pixels (optimal for A4 width)
  scale: 1.5, // Quality/performance balance
  margin: { top: 20, right: 15, bottom: 20, left: 15 }, // mm
  pageBreak: true
});

Complete API Reference

Hook Configuration

| Option | Type | Default | Description | |--------|------|---------|-------------| | fileName | string | 'document.pdf' | Output filename | | format | string/array | 'a4' | Page size (a3,a4,letter or [w,h] in mm) | | orientation | string | 'portrait' | 'portrait' or 'landscape' | | margin | number/object | 0 | Margins in mm | | fixedWidth | number | undefined | Constrained width in pixels | | scale | number | 2 | Render quality multiplier | | pageBreak | boolean | true | Auto page break config | | imageQuality | number | 1 | Image quality (0-1) | | debug | boolean | false | Enable debug logging | | compressPdf | boolean | true | Compress the pdf size|

Content Configuration

interface PdfContentItem {
  selector: string;       // CSS selector or image path
  mapping: boolean;      // true = all matches, false = first match
  type: 'element'|'image';
  imageOptions?: {        // Only for type: 'image'
    width?: number;      // mm
    height?: number;     // mm
    x?: number;          // mm
    y?: number;          // mm
    format?: 'JPEG'|'PNG';
    maintainAspectRatio?: boolean;
  };
}

Best Practices

  1. For images:

    • Place assets in public folder
    • Use absolute paths (/images/photo.jpg)
    • Set explicit dimensions in imageOptions
  2. For performance:

    {
      scale: 1, // Lower quality but faster
      imageQuality: 0.8,
      fixedWidth: 800 // Smaller fixed width
    }

Troubleshooting

Issue | Solution ---|--- Images missing | Verify paths and CORS headers Content clipped | Increase margins or reduce fixedWidth PDF-only content not showing | Check CSS and media queries Performance problems | Reduce scale and imageQuality

License

MIT © Spexzee


Like this package? ⭐️ Star the repo
Need help? 📧 Contact me
Found a bug? 🐛 Open an issue