PDF Viewer in React and Understanding PDF.js Layers

Leader posted 2 min read

To create a PDF viewer in React.js using PDF.js, especially with support for layers (like text, annotations, and images), you need a good understanding of how PDF.js renders documents. Here’s a full guide:


Understanding PDF.js Layers

PDF.js renders PDFs using HTML5. It separates rendering into three main layers:

Layer Purpose Output
canvas Renders PDF content (text, images, drawings) Bitmap
textLayer Overlays selectable text (for copy/paste or search) HTML
annotationLayer Adds interactive elements (links, form fields, etc.) HTML
XfaLayer (optional) For newer interactive forms (XFA-based) HTML

Best Way to Build a PDF Viewer in React

Option 1: Use pdfjs-dist + custom React component (for flexibility)

Option 2: Use a wrapper library like react-pdf for ease


Option 1: Full Control Using pdfjs-dist

Install:

npm install pdfjs-dist

Set up:

import { useEffect, useRef } from 'react';
import { getDocument } from 'pdfjs-dist';
import 'pdfjs-dist/web/pdf_viewer.css';
import * as pdfjsLib from 'pdfjs-dist/build/pdf';
import * as pdfjsViewer from 'pdfjs-dist/web/pdf_viewer';

pdfjsLib.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjsLib.version}/pdf.worker.min.js`;

function PDFViewer({ pdfUrl }) {
  const containerRef = useRef(null);

  useEffect(() => {
    const container = containerRef.current;

    const eventBus = new pdfjsViewer.EventBus();
    const pdfLinkService = new pdfjsViewer.PDFLinkService({ eventBus });
    const pdfViewer = new pdfjsViewer.PDFViewer({
      container,
      eventBus,
      linkService: pdfLinkService,
      textLayerMode: 2, // enables selectable text
      annotationMode: 2, // enables annotations
    });

    pdfLinkService.setViewer(pdfViewer);

    getDocument(pdfUrl).promise.then(pdfDoc => {
      pdfViewer.setDocument(pdfDoc);
      pdfLinkService.setDocument(pdfDoc);
    });
  }, [pdfUrl]);

  return (
    <div className="pdfViewer" ref={containerRef} style={{ height: '100vh', overflow: 'scroll' }} />
  );
}

This supports textLayer, annotationLayer, and has full control.


Option 2: Easier with react-pdf (but less control over layers)

Install:

npm install @react-pdf-viewer/core @react-pdf-viewer/default-layout

Use:

import { Worker, Viewer } from '@react-pdf-viewer/core';
import { defaultLayoutPlugin } from '@react-pdf-viewer/default-layout';
import '@react-pdf-viewer/core/lib/styles/index.css';
import '@react-pdf-viewer/default-layout/lib/styles/index.css';

const MyPdfViewer = ({ fileUrl }) => {
  const defaultLayoutPluginInstance = defaultLayoutPlugin();

  return (
    <Worker workerUrl={`https://unpkg.com/pdfjs-dist@3.4.120/build/pdf.worker.min.js`}>
      <div style={{ height: '750px' }}>
        <Viewer fileUrl={fileUrl} plugins={[defaultLayoutPluginInstance]} />
      </div>
    </Worker>
  );
};

This is easier to integrate but hides some PDF.js layer-level control under the hood.


Tips

  • To enable copy/select, ensure textLayerMode: 2 is used (or equivalent in viewer).
  • For annotations (e.g., links, form fields), make sure annotationMode: 2.
  • Add styles from pdfjs-dist/web/pdf_viewer.css for correct rendering.
  • Use a PDF worker for performance (PDF rendering off main thread).

Recommendation

If you want Use
Full control (text, links, annotations, custom layout) pdfjs-dist with custom setup
Simplicity & decent features react-pdf-viewer or @react-pdf-viewer
Heavy customization (e.g., drawing, signature, comments) Go with pdfjs-dist + custom UI

If you read this far, tweet to the author to show them you care. Tweet a Thanks

Adding images of code run could be better for this article. Anyways, nice share.

More Posts

Build a Multilingual Blog Viewer in React using Intlayer

paruidev - Aug 17

CSRF Token in Web Development: Secure Your React, Next.js, Django & Laravel Apps

Raj Aryan - Jun 9

Mastering React: A Mindset for Component-Centric Development

Losalini Rokocakau - May 3, 2024

Build a Full-Stack Video Streaming App with React.js, Node.js, Next.js, MongoDB, Bunny CDN, and Material UI

torver213 - Mar 29

Implementing Secure Authentication in Modern Web Apps: OAuth 2.0 & JWT with Angular and Node.js

Sunny - Oct 2
chevron_left