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

pdfjs-highlighter

v1.0.2

Published

PDF viewer with rectangle highlights, zoom, navigation, and linked form fields

Readme

pdfjs-highlighter

npm version npm license

A React PDF viewer with rectangle highlights, zoom, page navigation, and optional link-to-form-field navigation. Built on PDF.js with full TypeScript support.

Install

npm install pdfjs-highlighter pdfjs-dist react react-dom

Peer dependencies: react (^18 or ^19), react-dom, pdfjs-dist — install them in your app if not already present.

Quick start

import { PdfHighlighterViewer, Highlight } from "pdfjs-highlighter";

const highlights: Highlight[] = [
  { id: "h1", page: 1, x: 0.1, y: 0.2, width: 0.3, height: 0.1, coordinateSpace: "percent" },
];

export function App() {
  return (
    <div style={{ height: 600 }}>
      <PdfHighlighterViewer
        source={{ type: "url", url: "/document.pdf" }}
        highlights={highlights}
        toolbar
      />
    </div>
  );
}

Features

  • PDF rendering — URL, ArrayBuffer, or base64 source
  • Rectangle highlights — Percent or PDF coordinate space; per-highlight color and opacity
  • Zoom — Toolbar controls and Ctrl + mouse wheel (configurable)
  • Page navigation — Prev/next, go to page, optional custom toolbar
  • Highlight navigation — Click a highlight to scroll into view and focus it; optional zoom-on-focus
  • Link to form fields — Optional linkedFieldId to scroll to and focus a DOM element (e.g. input) when a highlight is clicked
  • Ref APIgoToPage, goToHighlight, goToLinkedField for programmatic control
  • TypeScript — Typed props, ref, and highlight model

Demo

The pdf-highlighter-demo app in this repo shows a discrepancy-review UI: side-by-side PDF viewers (Instruction vs Confirmation) with highlights and form fields linked via linkedFieldId. Run it with npm run dev from the pdf-highlighter-demo folder.

Discrepancy review demo — Fields to Review panel and side-by-side Instruction / Confirmation PDF viewers with highlights

Table of contents

Props and API

Component: PdfHighlighterViewer

| Prop | Type | Default | Description | |------|------|---------|-------------| | source | PdfFileSource | required | { type: "url", url } or { type: "data", data } or { type: "base64", base64 } | | highlights | Highlight[] | [] | Rectangle highlights to overlay | | initialPage | number | 1 | First page to show | | initialZoom | number | 1 | Initial zoom level | | zoomStep | number | 0.2 | Zoom in/out step | | minZoom | number | 0.5 | Minimum zoom | | maxZoom | number | 3 | Maximum zoom | | toolbar | boolean | true | Show built-in toolbar | | showZoomControls | boolean | true | Show zoom buttons and reset in toolbar | | enableHighlightNavigation | boolean | true | Click highlight to go to page and scroll to it | | highlightScrollBehavior | "smooth" \| "auto" | "smooth" | Scroll behavior when focusing a highlight | | highlightFocusZoom | number | — | Optional zoom level when focusing a highlight | | enableCtrlWheelZoom | boolean | true | Ctrl + wheel zooms the viewer | | enableFieldNavigation | boolean | false | Click highlight with linkedFieldId scrolls to and focuses that DOM element | | onHighlightClick | (highlight: Highlight) => void | — | Called on every highlight click | | onLinkedFieldFocus | (highlight, element \| null) => void | — | Called after navigating to a linked field | | linkedFieldFocusClassName | string | — | CSS class for linked-field focus effect (override default) | | renderHighlightTooltip | (highlight) => ReactNode | — | Custom tooltip for highlights | | renderToolbar | (props) => ReactNode | — | Custom toolbar (replaces default) | | className | string | — | Root element class | | style | React.CSSProperties | — | Root element style |

Ref: PdfViewerRef

  • goToPage(page: number) — Switch to page
  • goToHighlight(highlightId: string) — Go to page and scroll to highlight
  • goToLinkedField(highlightId: string) — Scroll to and focus the linked DOM element (if highlight has linkedFieldId)

Types

  • Highlightid, page, x, y, width, height, color?, opacity?, coordinateSpace? ("percent" | "pdf"), data?, linkedFieldId?
  • PdfFileSource{ type: "url", url } | { type: "data", data } | { type: "base64", base64 }

Highlights

Highlights are rectangles overlaid on the PDF. Use percent (0–1, top-left origin) or PDF (points, bottom-left origin).

const highlights: Highlight[] = [
  {
    id: "total",
    page: 1,
    x: 0.1,
    y: 0.35,
    width: 0.8,
    height: 0.06,
    color: "#f97316",
    opacity: 0.4,
    coordinateSpace: "percent", // default
  },
];

With enableHighlightNavigation (default), clicking a highlight navigates to its page, scrolls it into view, and runs a short focus animation. Use highlightFocusZoom to set a zoom level when focusing.

Zoom and navigation

  • Toolbar: Page prev/next, page input, zoom in/out, reset zoom, download (if source allows).
  • Ctrl + wheel: Zooms over the viewer (when enableCtrlWheelZoom is true).
  • Zoom is shared between PDF canvas and highlight overlay so highlights stay aligned.

Ref API

import { useRef } from "react";
import { PdfHighlighterViewer, PdfViewerRef } from "pdfjs-highlighter";

function Viewer() {
  const ref = useRef<PdfViewerRef>(null);

  return (
    <>
      <button onClick={() => ref.current?.goToPage(2)}>Page 2</button>
      <button onClick={() => ref.current?.goToHighlight("total")}>Go to highlight</button>
      <button onClick={() => ref.current?.goToLinkedField("total")}>Go to field</button>
      <PdfHighlighterViewer
        ref={ref}
        source={{ type: "url", url: "/doc.pdf" }}
        highlights={highlights}
      />
    </>
  );
}

Linking highlights to form fields

When enableFieldNavigation is true, a highlight can have linkedFieldId set to the id of a DOM element (e.g. an input). Clicking that highlight (or calling goToLinkedField(id)) scrolls the element into view, focuses it, and applies a short focus effect.

const highlights: Highlight[] = [
  {
    id: "h1",
    page: 1,
    x: 0.1,
    y: 0.35,
    width: 0.84,
    height: 0.055,
    coordinateSpace: "percent",
    linkedFieldId: "transaction-value",
  },
];

<input id="transaction-value" placeholder="Enter value" />

<PdfHighlighterViewer
  source={{ type: "url", url: "/doc.pdf" }}
  highlights={highlights}
  enableFieldNavigation
  onLinkedFieldFocus={(highlight, element) => {
    if (element) element.setAttribute("aria-describedby", "live-region");
  }}
/>

If the element is missing, the library does nothing (no error). Use linkedFieldFocusClassName to style the focus effect or onLinkedFieldFocus for accessibility (e.g. live region).

Custom toolbar

Replace the default toolbar with renderToolbar:

import { PdfHighlighterViewer, PdfHighlighterViewerToolbarProps } from "pdfjs-highlighter";

function CustomToolbar(props: PdfHighlighterViewerToolbarProps) {
  const { page, pageCount, onPrevPage, onNextPage, zoom, onZoomIn, onZoomOut, onDownload } = props;
  return (
    <div className="my-toolbar">
      <button onClick={onPrevPage}>Prev</button>
      <span>{page} / {pageCount}</span>
      <button onClick={onNextPage}>Next</button>
      <button onClick={onZoomOut}>−</button>
      <span>{Math.round(zoom * 100)}%</span>
      <button onClick={onZoomIn}>+</button>
      <button onClick={onDownload}>Download</button>
    </div>
  );
}

<PdfHighlighterViewer
  source={{ type: "url", url: "/doc.pdf" }}
  renderToolbar={(p) => <CustomToolbar {...p} />}
/>

Styling

  • The root element accepts className and style (e.g. for Tailwind or dark mode).
  • Optional base styles (focus ring, linked-field effect) can be imported:
import "pdfjs-highlighter/styles.css";
  • Override the linked-field focus effect with linkedFieldFocusClassName.

License

MIT · GitHub · npm