Skip to content

Dappner/react-pdf-annotator

 
 

Repository files navigation

react-pdf-highlighter

Set of React components for PDF annotation.

Note: This is a fork of agentcooper/react-pdf-highlighter with significant UX improvements.

Features

  • Built on top of PDF.js
  • Text and image highlights
  • Popover text for highlights
  • Scroll to highlights

Fork Improvements

This fork includes the following enhancements:

Highlight Interaction

  • Hover-based action bar: Shows on hover with 200ms delay (prevents flickering), instead of right-click
  • Smooth hover transitions: 150ms grace period allows mouse to move from highlight to action bar
  • Click protection: Clicking action bar buttons no longer dismisses the popup

Selection Flow

  • Mouseup-based selection: Toolbar appears only after releasing mouse, not while dragging
  • Morphing toolbar: After saving, toolbar transitions from "save mode" to "edit mode"
  • No double-yellow: Browser selection is cleared on save to prevent color stacking

Positioning

  • Centered popups: Action bars are horizontally centered above highlights
  • Smart clamping: Popups stay within page bounds while maintaining optimal position

Visual

  • Better highlight color: More vibrant yellow (rgba(255, 212, 0, 0.4))
  • Hover feedback: Highlights brighten slightly on hover

New Props

Prop Description
renderPopup Simpler alternative to highlightTransform for hover action bars
onTextLayerReady Callback when a page's text layer is rendered
onDocumentReady Callback when document is ready
forceRenderOnLoad Force re-render highlights when all pages loaded
onHighlightHover Callback when a highlight is hovered
onHighlightBlur Callback when a highlight loses hover
disallowOverlappingHighlights Prevent creating overlapping text highlights on the same line
onOverlap Callback fired when a selection overlaps an existing highlight

Install

npm install react-pdf-highlighter

Importing CSS

import "react-pdf-highlighter/dist/style.css";

Example

npm install
npm start

The example demonstrates:

  • Slide-over panel pattern
  • Zoom controls (Ctrl+scroll or buttons)
  • Morphing toolbar (save → edit)
  • Comment dialog modal
  • In-memory highlight persistence

Basic Usage

import { PdfHighlighter, PdfLoader } from "react-pdf-highlighter";
import "react-pdf-highlighter/dist/style.css";

<PdfLoader url={pdfUrl} beforeLoad={<Spinner />}>
  {(pdfDocument) => (
    <PdfHighlighter
      pdfDocument={pdfDocument}
      enableAreaSelection={(event) => event.altKey}
      onScrollChange={() => {}}
      scrollRef={(scrollTo) => { /* store scrollTo */ }}
      onSelectionFinished={(position, content, hideTipAndSelection, transformSelection) => (
        <MySelectionToolbar
          onSave={() => {
            saveHighlight({ position, content });
            hideTipAndSelection();
          }}
        />
      )}
      renderPopup={(highlight) => (
        <MyActionBar highlight={highlight} />
      )}
      highlights={highlights}
    />
  )}
</PdfLoader>

useHighlights Helper

useHighlights is an optional convenience hook for managing highlight state while keeping your data source external (React Query, Redux, etc.).

import { useState } from "react";
import { useHighlights } from "react-pdf-highlighter";

const [highlights, setHighlights] = useState<IHighlight[]>([]);
const {
  addHighlight,
  updateHighlight,
  deleteHighlight,
  saveComment,
} = useHighlights({
  highlights,
  setHighlights,
});

This pattern lets you merge/split your own persistence models in setHighlights and rehydrate via async fetches.

useZoom Helper

useZoom provides a small controller for zooming the PDF viewer (buttons + ctrl/cmd + wheel).

import { useRef } from "react";
import { useZoom } from "react-pdf-highlighter";

const containerRef = useRef<HTMLDivElement | null>(null);
const { pdfScaleValue, zoomLabel, zoomIn, zoomOut, fitWidth } = useZoom(
  containerRef,
  true,
);

How It Works (Library)

High-level flow

  • PdfLoader loads a PDFDocumentProxy using PDF.js and hands it to your render prop.
  • PdfHighlighter owns a PDF.js PDFViewer, attaches selection/scroll listeners, and renders highlights into a per-page overlay layer.
  • Text selections call onSelectionFinished with a ScaledPosition and text content; area selections are handled by MouseSelection and yield image content.
  • Highlights are rendered via highlightTransform (custom) or the default transform, which chooses Highlight for text or AreaHighlight for images and can show a popup via renderPopup.

Data model and coordinates

  • ScaledPosition is stored in PDF/viewport-independent units (optionally usePdfCoordinates).
  • Position is viewport pixels used for rendering. scaledToViewport and viewportToScaled live in src/lib/coordinates.ts.
  • IHighlight is the base interface for highlight objects; HighlightHooks exposes onCreate, onUpdate, and onDelete.

Project layout (library)

  • src/index.ts is the public entry point; it re-exports components, types, and the global CSS.
  • src/components/ contains PdfHighlighter, PdfLoader, and the overlay UI (Highlight, AreaHighlight, TipContainer).
  • src/lib/ contains PDF.js DOM helpers, coordinate conversions, and geometry utilities.
  • src/style/ holds CSS modules plus index.css which imports the PDF.js viewer styles.

Build outputs

  • Vite builds the package and emits JS + CSS into dist/.
  • Types are emitted via vite-plugin-dts and exposed at dist/index.d.ts.
  • The published package exposes dist/style.css for styling.

API Reference

See ./example/src/App.tsx for a complete implementation example.

API Improvement Ideas (Future)

These are optional, backward-compatible ideas that could simplify usage and improve extensibility:

  • Decouple UI from selection: make onSelectionFinished return data/payload, with an optional renderSelection for UI.
  • Consolidate highlight types: collapse HighlightPayload/HighlightBase/IHighlight into a clearer, generic model (typed meta).
  • Unified PDF.js options: accept a single pdfjsOptions object (worker/cMap/viewer) to reduce prop surface area.
  • Public coordinate helpers: export scaledToViewport/viewportToScaled from the public API for consumers.

License

MIT

About

Set of React components for PDF highlighting and annotation

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 91.8%
  • CSS 8.0%
  • HTML 0.2%