react-pdf-highlighter

repository·main·Indexed 23 days ago

https://github.com/agentcooper/react-pdf-highlighter

A set of React components built on top of PDF.js for PDF annotation. It enables text and image highlights, popover text for highlights, and programmatic navigation to specific highlights within a document. Key components include PdfHighlighter for the main integration, PdfLoader for document loading, and AreaHighlight for draggable/resizable highlight areas.

Tokens
3.7K
Snippets
6
Records
20
Agent score
80%

What's inside react-pdf-highlighter

  1. Overview of react-pdf-highlighter features

    main

    The react-pdf-highlighter library provides a set of React components designed for PDF annotation. Key features include:

    • Built on top of PDF.js
    • Support for both text and image highlights
    • Popover text functionality for existing highlights
    • Ability to scroll to highlights within the document
  2. Understand Highlight Position types: ScaledPosition vs Position

    main

    The library uses two primary ways to represent where a highlight is located on a page:

    1. ScaledPosition: Used for creating and storing highlights. It uses Scaled rectangles which are relative to the viewport/display size. It includes a usePdfCoordinates boolean to indicate if the coordinates should be treated as PDF-native.
    2. Position: Used for viewport-based rendering. It uses LTWHP (Left, Top, Width, Height) rectangles and is tied to a specific pageNumber.

    Both types contain a boundingRect (the overall area) and an array of rects (the individual lines or segments of the highlight).

    export interface Scaled {
      x1: number;
      y1: number;
      x2: number;
      y2: number;
      width: number;
      height: number;
      pageNumber?: number;
    }
    
    export interface ScaledPosition {
      boundingRect: Scaled;
      rects: Array<Scaled>;
      pageNumber: number;
      usePdfCoordinates?: boolean;
    }
    
    export interface Position {
      boundingRect: LTWHP;
      rects: Array<LTWHP>;
      pageNumber: number;
    }
  3. Implement custom highlight rendering with highlightTransform

    main

    The highlightTransform prop is a required function that determines how each highlight is rendered in the UI. It is called for every highlight in the highlights array.

    Arguments:

    • highlight: The current highlight object (of type T_ViewportHighlight<T_HT>).
    • index: The index of the highlight in the array.
    • setTip: A function to show a floating 'tip' (popover/menu) at the highlight's position.
      • Signature: (highlight: T_ViewportHighlight<T_HT>, callback: (highlight: T_ViewportHighlight<T_HT>) => JSX.Element) => void
    • hideTip: A function to dismiss the current tip.
    • viewportToScaled: A utility to convert coordinates from the PDF viewport to scaled coordinates.
    • screenshot: A utility to capture an image of a specific area (LTWH) on a page.
    • isScrolledTo: A boolean indicating if this specific highlight is currently the one being scrolled into view.

    Return Value:

    • A JSX.Element representing the visual highlight (e.g., a colored overlay or a marker).
  4. Configure the PdfLoader workerSrc

    main

    The PdfLoader component requires a PDF.js worker to function. By default, it uses a hosted version from unpkg: https://unpkg.com/pdfjs-dist@4.4.168/build/pdf.worker.min.mjs.

    If you need to use a local worker or a different version of pdfjs-dist, you must provide the workerSrc prop. This ensures the GlobalWorkerOptions.workerSrc is correctly set for the pdfjs-dist library.

  5. Use the PdfLoader component to load PDF documents

    main

    The PdfLoader component is responsible for loading a PDF document using pdfjs-dist. It manages the lifecycle of the PDF document, including loading, error handling, and cleaning up resources when the component unmounts.

    It uses a render prop pattern: you provide a children function that receives the loaded pdfDocument (of type PDFDocumentProxy), allowing you to render the PDF once it is ready.

    Key Props:

    • url (required): The URL of the PDF document to load.
    • children: A function that receives the pdfDocument and returns a JSX.Element.
    • beforeLoad: A JSX.Element to display while the PDF is loading.
    • errorMessage: An optional JSX.Element to display if an error occurs. If provided, it can receive the error as a prop via React.cloneElement.
    • workerSrc: The path to the PDF.js worker script. Defaults to a CDN version of pdfjs-dist@4.4.168.
    • onError: A callback function invoked when an error occurs during loading.
    • cMapUrl / cMapPacked: Configuration for character maps used in PDF rendering.
  6. Use the PdfHighlighter component

    main

    The PdfHighlighter component is the primary entry point for integrating PDF highlighting capabilities into a React application. It requires a pdfDocument (from pdfjs-dist) and a set of callback props to handle user interactions like text selection, area selection, and scrolling.

    Key Props

    • pdfDocument: The PDFDocumentProxy instance.
    • highlights: An array of highlight objects (extending IHighlight).
    • highlightTransform: A function used to render the UI for each highlight. It provides access to tools like viewportToScaled, screenshot, and setTip.
    • onSelectionFinished: A callback triggered when a user finishes selecting text or an area. It provides the scaledPosition, content (text or image), and functions to hide the selection or transform it into a 'ghost' highlight.
    • scrollRef: A callback that provides a scrollTo function, allowing you to programmatically navigate to specific highlights.
    • onScrollChange: A callback triggered when the PDF viewer scrolls.
    • pdfScaleValue: Controls the PDF zoom level (defaults to "auto").
    • enableAreaSelection: An optional function to enable non-text (area) selection. It receives the MouseEvent and should return true if selection should proceed.
    • pdfViewerOptions: Optional configuration passed directly to the underlying pdfjs-dist PDFViewer.

    Example Usage

    <PdfHighlighter
      pdfDocument={myPdfDocument}
      highlights={myHighlights}
      highlightTransform={(highlight, index, setTip, hideTip, viewportToScaled, screenshot, isScrolledTo) => (
        <div key={highlight.id} onClick={() => setTip(highlight.position, <MyTipComponent />)}>
          {/* Custom highlight UI */}
        </div>
      )}
      onSelectionFinished={(position, content, hideTipAndSelection, transformSelection) => {
        console.log('New selection:', position, content);
        return <MySelectionMenu onSave={...} />;
      }}
      scrollRef={(scrollTo) => {
        // Use scrollTo(highlight) to navigate
      }}
      onScrollChange={() => console.log('scrolled')}
    />
  7. Handle new selections with onSelectionFinished

    main

    The onSelectionFinished prop is the primary way to capture user-created highlights. It is invoked after a user completes a text selection or an area selection.

    Arguments:

    • position: The ScaledPosition of the selection.
    • content: An object containing either text (for text selections) or image (a base64 string for area selections).
    • hideTipAndSelection: A function to clear the current selection UI and any active tips.
    • transformSelection: A function that turns the current selection into a 'ghost highlight' (a temporary visual state before it is officially saved).

    Return Value:

    • A JSX.Element | null. If you return a component, it will be rendered as a 'tip' (popover) at the selection location, allowing the user to perform actions like 'Save Highlight'.
  8. Enable area (non-text) selection

    main

    To allow users to select rectangular areas (like images or diagrams) instead of just text, provide the enableAreaSelection prop.

    enableAreaSelection should be a function that takes a MouseEvent and returns a boolean. If it returns true, the component will activate the MouseSelection logic, which allows dragging to define a rectangular area.

    When an area is selected, onSelectionFinished will be called with the image property populated in the content argument, containing a PNG screenshot of the selected area.

    <PdfHighlighter
      // ... other props
      enableAreaSelection={(event) => {
        // Logic to determine if this mouse event should trigger area selection
        // e.g., checking if a modifier key is pressed
        return event.altKey;
      }}
    />