How to use PDF.js to highlight text programmatically

Table of contents

    This guide covers two approaches for working with highlight annotations in PDFs: using PDF.js to render existing highlights with HTML overlays, and using Nutrient Web SDK to programmatically create and embed real highlight annotations into a PDF.
    How to use PDF.js to highlight text programmatically
    TL;DR
    • PDF.js (free viewer) can simulate highlights with HTML overlays but cannot embed or save them in the PDF. It’s great for quick, lightweight visuals.
    • Nutrient Web SDK (commercial) offers a full annotation API that writes real highlight objects into a file, with precise positioning, flattening, and other advanced features. Use it when you need persistent, production-grade PDF annotations.

    PDF.js is primarily designed as a PDF viewer, and its manipulation capabilities may be limited compared to those of dedicated PDF editing software.

    Downloading the PDF.js library

    Download(opens in a new tab) the PDF.js library as a ZIP file, clone the repository using Git, or install it via npm:

    Terminal window
    npm install pdfjs-dist

    If you downloaded the ZIP file, extract it and copy the pdf.mjs and pdf.worker.mjs files from the build/ folder to your project directory. If you installed via npm, copy them from node_modules/pdfjs-dist/build/:

    Terminal window
    cp node_modules/pdfjs-dist/build/pdf.mjs node_modules/pdfjs-dist/build/pdf.worker.mjs .

    Loading and rendering PDF documents

    Load the PDF document and render it in a canvas element. Replace annotation.pdf with your PDF document path (you can use this demo document as an example):

    <!doctype html>
    <html>
    <head>
    <title>PDF.js Highlight Annotations</title>
    <style>
    body {
    margin: 0;
    padding: 20px;
    position: relative;
    }
    #canvas {
    border: 1px solid #ccc;
    }
    </style>
    </head>
    <body>
    <!-- Canvas to place the PDF -->
    <canvas id="canvas"></canvas>
    <script type="module">
    import * as pdfjsLib from './pdf.mjs';
    // Get the canvas element.
    const canvas = document.getElementById('canvas');
    // Get the PDF file URL.
    const pdfUrl = 'annotation.pdf'; // Replace with the URL of your PDF document
    // Configure the PDF.js worker source.
    pdfjsLib.GlobalWorkerOptions.workerSrc = './pdf.worker.mjs';
    // Load the PDF file using PDF.js.
    pdfjsLib.getDocument(pdfUrl).promise.then(function (pdfDoc) {
    // Get the first page of the PDF file.
    pdfDoc.getPage(1).then(function (page) {
    const viewport = page.getViewport({ scale: 1 });
    // Set the canvas dimensions to match the PDF page size.
    canvas.width = viewport.width;
    canvas.height = viewport.height;
    // Set the canvas rendering context.
    const ctx = canvas.getContext('2d');
    const renderContext = {
    canvasContext: ctx,
    viewport: viewport,
    };
    // Render the PDF page to the canvas.
    page.render(renderContext).promise.then(function () {
    console.log('Rendering complete');
    // Call the function to render highlight annotations after the PDF page is rendered.
    renderHighlightAnnotations(page, viewport);
    });
    });
    });
    </script>
    </body>
    </html>

    Adding highlight annotations programmatically

    Use the getAnnotations() method to retrieve existing annotations from the PDF page. Add the following function inside your <script type="module"> block:

    function renderHighlightAnnotations(page, viewport) {
    // Anchor highlights to an overlay layered on top of the canvas so they stay
    // aligned when the page is scrolled, zoomed, or otherwise reflowed.
    const parent = canvas.parentNode;
    if (getComputedStyle(parent).position === 'static') {
    parent.style.position = 'relative';
    }
    const overlay = document.createElement('div');
    overlay.style.position = 'absolute';
    overlay.style.left = canvas.offsetLeft + 'px';
    overlay.style.top = canvas.offsetTop + 'px';
    overlay.style.width = viewport.width + 'px';
    overlay.style.height = viewport.height + 'px';
    overlay.style.pointerEvents = 'none';
    parent.appendChild(overlay);
    page.getAnnotations().then(function (annotations) {
    annotations.forEach(function (annotation) {
    if (annotation.subtype === 'Highlight') {
    // Convert the PDF user-space rectangle to viewport (canvas)
    // coordinates. This handles the bottom-up Y axis, the current
    // scale, and any page rotation in one step.
    const [x1, y1, x2, y2] = viewport.convertToViewportRectangle(
    annotation.rect,
    );
    const highlight = document.createElement('div');
    highlight.style.position = 'absolute';
    highlight.style.left = Math.min(x1, x2) + 'px';
    highlight.style.top = Math.min(y1, y2) + 'px';
    highlight.style.width = Math.abs(x2 - x1) + 'px';
    highlight.style.height = Math.abs(y2 - y1) + 'px';
    highlight.style.backgroundColor = 'yellow';
    highlight.style.opacity = '0.5';
    highlight.style.pointerEvents = 'none';
    overlay.appendChild(highlight);
    }
    });
    });
    }

    The renderHighlightAnnotations(page, viewport) function retrieves all annotations from the specified page. If the annotation’s subtype matches 'Highlight', it creates a yellow rectangle (highlight) using a div element. PDF rectangles live in user space (origin at the bottom-left, bottom-up Y axis), so call viewport.convertToViewportRectangle() to translate each one into the canvas’s coordinate system — this also accounts for the current scale and any page rotation. The highlights are appended to an overlay div anchored to the canvas, so they stay aligned during scrolling and zoom rather than being positioned in viewport coordinates against the document body.

    After executing these steps, the highlight annotations present in the PDF document will be displayed as yellow rectangles with 50 percent opacity on top of the PDF pages.

    Nutrient Web SDK

    Nutrient provides a commercial JavaScript PDF viewer library for web applications. Nutrient Web SDK includes 30+ features for viewing, annotating, editing, and signing PDFs directly in the browser. The following sections cover how to set up the SDK and add highlight annotations programmatically.

    Requirements

    Adding Nutrient to your project

    Install the @nutrient-sdk/viewer package via npm, or download the SDK manually:

    Terminal window
    npm i @nutrient-sdk/viewer

    To run Nutrient Web SDK in the browser, copy the required library files (artifacts) to your assets folder:

    Terminal window
    cp -R ./node_modules/@nutrient-sdk/viewer/dist/ ./assets/

    Make sure your assets/ folder contains:

    • nutrient-viewer.js (entry point)
    • A nutrient-viewer-lib/ directory with the required runtime assets

    Integrating into your project

    1. Add the PDF document you want to display (e.g. document.pdf) to the root of your project. You can use our demo document as an example.

    2. Add an empty <div> element to your HTML where the viewer will mount:

      <div id="nutrient" style="height: 100vh;"></div>
    3. Import the SDK and initialize it using NutrientViewer.load():

    <!doctype html>
    <html lang="en">
    <head>
    <title>Nutrient PDF Viewer</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    </head>
    <body>
    <div id="nutrient" style="height: 100vh;"></div>
    <script type="module">
    import './assets/nutrient-viewer.js';
    const baseUrl = `${window.location.protocol}//${window.location.host}/assets/`;
    NutrientViewer.load({
    container: '#nutrient',
    document: 'document.pdf',
    baseUrl,
    })
    .then((instance) => {
    console.log('Nutrient Viewer loaded', instance);
    })
    .catch((error) => {
    console.error(error.message);
    });
    </script>
    </body>
    </html>

    Nutrient PDF viewer displaying a document

    Adding highlight annotations programmatically

    The NutrientViewer.Annotations.HighlightAnnotation constructor creates a new highlight annotation object with properties like page index and rectangles to highlight:

    NutrientViewer.load({
    container: '#nutrient',
    document: 'document.pdf',
    baseUrl,
    })
    .then(async function (instance) {
    try {
    console.log('Nutrient loaded', instance);
    const rects = NutrientViewer.Immutable.List([
    new NutrientViewer.Geometry.Rect({
    left: 10,
    top: 120,
    width: 200,
    height: 10,
    }),
    new NutrientViewer.Geometry.Rect({
    left: 10,
    top: 150,
    width: 200,
    height: 10,
    }),
    ]);
    const annotation = new NutrientViewer.Annotations.HighlightAnnotation(
    {
    pageIndex: 0,
    rects: rects,
    boundingBox: NutrientViewer.Geometry.Rect.union(rects),
    },
    );
    await instance.create(annotation);
    console.log('Highlight annotation added successfully.');
    } catch (error) {
    console.error('Error adding highlight annotation:', error.message);
    }
    })
    .catch(function (error) {
    console.error('NutrientViewer failed to load:', error.message);
    });

    The provided rects array defines the bounding boxes of the areas to be highlighted, and the pageIndex property specifies the page where the highlight annotation will be added.

    Serving your website

    1. Install the serve package:

      Terminal window
      npm install --global serve
    2. Serve the contents of the current directory:

      Terminal window
      serve -l 8080 .
    3. Navigate to http://localhost:8080 to view the website.

    resulting image showing highlight annotation added to PDF

    Conclusion

    This post covered two methods for programmatically adding highlight annotations to PDFs. PDF.js(opens in a new tab) retrieves existing highlight annotations and renders them as HTML overlays, providing a lightweight solution for web applications. Nutrient Web SDK offers a full annotation API that writes real highlight objects into the PDF file.

    To try Nutrient, contact our Sales team or launch our demo.

    FAQ

    What is the main advantage of using Nutrient Web SDK over PDF.js for adding highlight annotations?

    Nutrient Web SDK provides a full annotation API that embeds real annotations into PDF files, while PDF.js only renders existing annotations as HTML overlays without modifying documents.

    How do I integrate Nutrient Web SDK into my existing project?

    Install the @nutrient-sdk/viewer package via npm, copy the library assets to your project, and initialize the viewer with NutrientViewer.load().

    Does Nutrient Web SDK support creating highlight annotations programmatically?

    Yes. Use the NutrientViewer.Annotations.HighlightAnnotation constructor to create highlight annotations programmatically.

    Can I use PDF.js to manage highlight annotations effectively?

    PDF.js focuses on PDF viewing and can render existing annotations, but it cannot create or embed new annotations into PDF files.

    Hulya Masharipov

    Hulya Masharipov

    Technical Writer

    Hulya is a frontend web developer and technical writer who enjoys creating responsive, scalable, and maintainable web experiences. She’s passionate about open source, web accessibility, cybersecurity privacy, and blockchain.

    Explore related topics

    Try for free Ready to get started?