@react-pdf/renderer vs react-pdf
Generating PDF Documents in React Applications
@react-pdf/rendererreact-pdfSimilar Packages:

Generating PDF Documents in React Applications

@react-pdf/renderer and react-pdf are both libraries used to handle PDFs in React, but they solve completely different problems. @react-pdf/renderer allows you to build PDF documents from scratch using React components and JSX, rendering them directly in the browser or on the server without needing external files. It is essentially a React renderer for PDFs. In contrast, react-pdf is a viewer library designed to display existing PDF files within a React application. It wraps the Mozilla PDF.js engine to render binary PDF data into HTML5 canvases, enabling features like zooming, paging, and text selection for documents that already exist.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@react-pdf/renderer016,724292 kB4274 months agoMIT
react-pdf011,137309 kB195 months agoMIT

Generating vs. Viewing PDFs: @react-pdf/renderer vs. react-pdf

When working with PDFs in the React ecosystem, developers often confuse @react-pdf/renderer and react-pdf because their names sound similar. However, they serve opposite ends of the document lifecycle. One is a creation engine that turns JSX into binary PDF data, while the other is a viewing engine that turns binary PDF data into visible HTML. Understanding this distinction is critical for architectural decisions.

πŸ› οΈ Core Purpose: Creation vs. Consumption

@react-pdf/renderer is a document generator. It acts as a custom React renderer (similar to react-dom), but instead of outputting HTML to the browser DOM, it outputs a binary PDF stream. You write standard React components, apply styles using a CSS-in-JS approach, and the library compiles this into a valid PDF file. It runs entirely in JavaScript, meaning it works in the browser, Node.js, or serverless environments without needing external binaries like Ghostscript or Puppeteer.

// @react-pdf/renderer: Creating a dynamic invoice
import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer';

const styles = StyleSheet.create({
  page: { padding: 30 },
  text: { fontSize: 12, marginBottom: 10 }
});

const InvoicePDF = ({ customerName, total }) => (
  <Document>
    <Page size="A4" style={styles.page}>
      <Text style={styles.text}>Invoice for: {customerName}</Text>
      <Text style={styles.text}>Total Due: ${total}</Text>
    </Page>
  </Document>
);

// Usage: <PDFDownloadLink document={<InvoicePDF name="John" total={50} />} fileName="inv.pdf" />

react-pdf is a document viewer. It does not create PDFs. Instead, it takes a URL or a binary blob of an existing PDF file and renders it onto an HTML5 <canvas> element using the PDF.js engine under the hood. Its primary job is to parse the complex binary structure of a PDF and paint it pixel-perfectly in the browser, handling interaction logic like scrolling, zooming, and page navigation.

// react-pdf: Displaying an existing manual
import { Document, Page, pdfjs } from 'react-pdf';
import 'react-pdf/dist/Page/AnnotationLayer.css';
import 'react-pdf/dist/Page/TextLayer.css';

// Set up the worker source (required for react-pdf)
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;

function PdfViewer() {
  const [numPages, setNumPages] = useState(null);

  function onDocumentLoadSuccess({ numPages }) {
    setNumPages(numPages);
  }

  return (
    <div>
      <Document file="/manuals/user-guide.pdf" onLoadSuccess={onDocumentLoadSuccess}>
        <Page pageNumber={1} />
      </Document>
      <p>Page 1 of {numPages}</p>
    </div>
  );
}

🎨 Styling and Layout: CSS Subset vs. Fixed Rendering

@react-pdf/renderer requires you to define layout using a specific subset of CSS properties. It uses Flexbox for layout management, which feels very natural to web developers. However, it does not support the full CSS specification. Properties like grid, complex selectors, or certain advanced positioning techniques are not available. You must think in terms of static pages with fixed dimensions (e.g., A4, Letter).

// @react-pdf/renderer: Flexbox layout for a report header
const styles = StyleSheet.create({
  header: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    padding: 20,
    backgroundColor: '#f0f0f0'
  },
  logo: { width: 50, height: 50 },
  title: { fontSize: 18, fontWeight: 'bold' }
});

const ReportHeader = () => (
  <View style={styles.header}>
    <Image style={styles.logo} src="/logo.png" />
    <Text style={styles.title}>Annual Report 2024</Text>
  </View>
);

react-pdf has no styling system for the document content itself because the content is already baked into the PDF file. You cannot change the font, color, or layout of the text inside the PDF using CSS. You can only style the container around the PDF viewer (e.g., the canvas wrapper, shadows, or margins). The internal rendering is determined strictly by the binary data of the source file.

// react-pdf: Styling the viewer container, NOT the PDF content
const viewerStyles = {
  container: {
    display: 'flex',
    justifyContent: 'center',
    backgroundColor: '#333',
    padding: '20px'
  },
  canvasWrapper: {
    boxShadow: '0 4px 6px rgba(0,0,0,0.3)',
    maxWidth: '100%'
  }
};

function StyledViewer({ file }) {
  return (
    <div style={viewerStyles.container}>
      <div style={viewerStyles.canvasWrapper}>
        <Document file={file}>
          <Page pageNumber={1} />
        </Document>
      </div>
    </div>
  );
}

⚑ Performance and Environment: Pure JS vs. Heavy Canvas

@react-pdf/renderer is lightweight in terms of runtime dependencies because it is pure JavaScript. It does not require a web worker to function, although it can be computationally expensive if you are generating massive documents with thousands of nodes on the main thread. It excels in server-side rendering (SSR) scenarios where you might generate a PDF on a Node.js server and stream it directly to the client as a download, saving the client from doing any work.

// @react-pdf/renderer: Server-side generation pattern (Node.js)
import { renderToStream } from '@react-pdf/renderer';

app.get('/generate-report', async (req, res) => {
  const data = await fetchData();
  const stream = await renderToStream(<MyReport data={data} />);
  
  res.setHeader('Content-Type', 'application/pdf');
  res.setHeader('Content-Disposition', 'attachment; filename=report.pdf');
  
  stream.pipe(res);
});

react-pdf relies heavily on Web Workers to parse PDF files without freezing the browser UI. Parsing a large PDF is CPU-intensive, so the library offloads this work to a separate thread. This requires proper configuration of the pdfjs-dist worker source. If not configured correctly, the main thread will block, causing the UI to freeze. It is strictly a client-side library; it cannot run in a Node.js environment to "view" a PDF since there is no DOM or Canvas.

// react-pdf: Configuring the worker is mandatory for performance
import { pdfjs } from 'react-pdf';

// Correctly pointing to the worker file prevents main-thread blocking
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
  'pdfjs-dist/build/pdf.worker.min.js',
  import.meta.url,
).toString();

// Without this, large files will cause the browser to hang during load
function OptimizedViewer({ fileUrl }) {
  return <Document file={fileUrl} loading={<div>Loading PDF...</div>}>
    <Page pageNumber={1} />
  </Document>;
}

πŸ” Text Interactivity: Static vs. Selectable

@react-pdf/renderer generates text that is natively selectable in the resulting PDF. Since the library constructs the PDF structure from scratch, it maps your <Text> components directly to PDF text objects. When a user opens the generated file in Adobe Reader or a browser viewer, they can highlight, copy, and search the text immediately.

// @react-pdf/renderer: Text is inherently selectable in output
const SelectableDoc = () => (
  <Document>
    <Page>
      <Text>This text is generated by React and will be selectable in the final PDF.</Text>
      <Text>You can copy this sentence directly from the downloaded file.</Text>
    </Page>
  </Document>
);

react-pdf also supports text selection, but it requires extra setup. By default, it renders the PDF as an image on a canvas. To enable text selection, copying, and accessibility, you must explicitly import and render the TextLayer alongside the Page component. This layer overlays invisible HTML text on top of the canvas pixels to mimic the PDF's text content.

// react-pdf: Enabling text selection requires the TextLayer component
import { Document, Page, TextLayer } from 'react-pdf';

function SelectableViewer({ file }) {
  return (
    <Document file={file}>
      <Page 
        pageNumber={1} 
        renderTextLayer={true} // Enables the text layer
        renderAnnotationLayer={true} // Enables links/forms
      />
    </Document>
  );
}
// Note: You must include the CSS for the text layer to position correctly

🌐 Similarities: Shared React Patterns

Despite their different goals, both libraries leverage React's component model to manage state and props.

1. βš›οΈ Component-Based Architecture

Both libraries allow you to encapsulate logic within reusable components. Whether you are building a reusable invoice row or a custom page navigator, the mental model remains consistent with standard React development.

// Both use props to pass data
// @react-pdf/renderer
const Row = ({ label, value }) => <Text>{label}: {value}</Text>;

// react-pdf
const PageNavigator = ({ currentPage, totalPages }) => (
  <div>Page {currentPage} of {totalPages}</div>
);

2. πŸ”„ State Management

Both rely on React state hooks (useState, useEffect) to handle dynamic updates. In the renderer, state might trigger a re-generation of the PDF blob. In the viewer, state controls the current page number or zoom level.

// Managing page state in react-pdf
const [pageNum, setPageNum] = useState(1);
<Document file={file}>
  <Page pageNumber={pageNum} />
</Document>
<button onClick={() => setPageNum(prev => prev + 1)}>Next</button>

3. πŸ“¦ Ecosystem Integration

Both integrate well with modern React tooling like TypeScript, Next.js, and Vite. They provide type definitions and work seamlessly within the standard build pipelines of create-react-app or custom Webpack configurations.

πŸ“Š Summary: Key Differences

Feature@react-pdf/rendererreact-pdf
Primary GoalCreate/Generate PDFs from scratchView/Render existing PDF files
InputReact Components (JSX)PDF File URL or Blob
OutputBinary PDF StreamHTML5 Canvas + DOM Layers
StylingCSS-in-JS (Flexbox subset)CSS for container only
EnvironmentBrowser, Node.js, ServerlessBrowser only (Client-side)
DependenciesPure JS (no external workers needed)Requires pdfjs-dist worker
Use CaseInvoices, Reports, TicketsDocument Readers, Archives

πŸ’‘ The Big Picture

The choice between these two libraries is not about which one is "better," but about which phase of the document lifecycle you are addressing.

@react-pdf/renderer is your factory. Use it when the document does not exist yet and needs to be assembled dynamically from your application's data. It replaces the need for backend-heavy solutions like Puppeteer or headless Chrome, allowing you to keep your PDF generation logic inside your React codebase.

react-pdf is your window. Use it when the document already exists and you need to present it to the user without forcing them to download it or leave your site. It provides a seamless, native-feeling experience for consuming static content.

Final Thought: In many mature applications, you will likely use both. You might use @react-pdf/renderer to generate a contract on the server, save it to storage, and then use react-pdf to display that same contract to the user for review and signature within the same React interface.

How to Choose: @react-pdf/renderer vs react-pdf

  • @react-pdf/renderer:

    Choose @react-pdf/renderer if your goal is to generate new PDF documents dynamically from data within your application. This is the correct tool for creating invoices, reports, certificates, or tickets where the content changes based on user input or database records. It allows you to define the layout using familiar React patterns and styles, making it ideal for projects that need to produce custom PDFs on the fly without relying on a backend service to generate the file.

  • react-pdf:

    Choose react-pdf if you need to display existing PDF files to your users inside your web application. This library is the standard solution for building document viewers, e-book readers, or admin panels where users need to inspect uploaded contracts, manuals, or forms. It is not designed to create or edit PDFs, but rather to provide a high-performance, interactive interface for viewing binary PDF assets that are already stored on your server or CDN.

README for @react-pdf/renderer

React renderer for creating PDF files on the browser and server

How to install

yarn add @react-pdf/renderer

How it works

import React from 'react';
import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer';

// Create styles
const styles = StyleSheet.create({
  page: {
    flexDirection: 'row',
    backgroundColor: '#E4E4E4',
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1,
  },
});

// Create Document Component
const MyDocument = () => (
  <Document>
    <Page size="A4" style={styles.page}>
      <View style={styles.section}>
        <Text>Section #1</Text>
      </View>
      <View style={styles.section}>
        <Text>Section #2</Text>
      </View>
    </Page>
  </Document>
);

Web. Render in DOM

import React from 'react';
import ReactDOM from 'react-dom';
import { PDFViewer } from '@react-pdf/renderer';

const App = () => (
  <PDFViewer>
    <MyDocument />
  </PDFViewer>
);

ReactDOM.render(<App />, document.getElementById('root'));

Node. Save in a file

import React from 'react';
import ReactPDF from '@react-pdf/renderer';

ReactPDF.render(<MyDocument />, `${__dirname}/example.pdf`);

Contributors

This project exists thanks to all the people who contribute. Looking to contribute? Please check our [contribute] document for more details about how to setup a development environment and submitting code.

Sponsors

Thank you to all our sponsors! [Become a sponsors]

Backers

Thank you to all our backers! [Become a backer]

License

MIT Β© Diego Muracciole