How to build a jQuery PDF viewer with PDF.js
This article was first published in November 2021 and was updated in October 2024.
If you’re looking to integrate a PDF viewer into your website or web application, you can easily do so using PDF.js, an open source library developed by Mozilla. When combined with jQuery, which simplifies event handling and DOM manipulation, this solution becomes incredibly versatile and user-friendly.
In this blog post, you’ll learn how to build a fully functional jQuery PDF viewer that can load, navigate, zoom, and print PDF files — all using PDF.js and jQuery. This method is simple to set up and offers great flexibility for customization.
Overview of the tutorial
In this tutorial, the process is in two parts:
-
Rendering and viewing a PDF in the browser using PDF.js.
-
Building a fully featured PDF viewer with additional functionalities like zoom, navigation, and print, enhanced by the Nutrient jQuery PDF library.
The Nutrient jQuery PDF library offers several advantages over PDF.js, including:
- A prebuilt and polished UI for an improved user experience
- 15+ prebuilt annotation tools to enable document collaboration
- Support for more file types with client-side PDF, MS Office, and image viewing
- Dedicated support from engineers to speed up integration
Requirements
To get started, you’ll need:
-
A package manager for installing the Nutrient library. You can use npm or Yarn. If you don’t want to use a package manager, you may choose to manually download the files into your project.
When you install Node.js,
npm
is installed by default.
Building a simple PDF viewer with jQuery and PDF.js
Understanding PDF.js
PDF.js is an open source JavaScript library that renders PDF documents directly in the browser using HTML5’s <canvas>
element. This section will show you how to use PDF.js along with jQuery to create a simple PDF viewer.
A primer on HTML5 canvas
The HTML5 <canvas>
element is a 2D drawing surface used to render graphics, images, and other visual content. PDF.js uses this to render PDF files.
<canvas id="canvas"></canvas>
You’ll need to access the canvas context to render content, and jQuery simplifies this:
const $ctx = $('#canvas')[0].getContext('2d');
This gives you access to the 2D drawing API, which you’ll use to render the PDF onto the canvas.
By the end of this section, you’ll be able to:
- View and display a PDF file in the browser.
- Zoom in and out.
- Navigate to a specific page.
- Navigate to the next and previous pages.
You can see the end result here and access the full code on GitHub.
Project setup
Before diving into the code, ensure you have the necessary libraries.
-
PDF.js — This will help you render the PDF document into the browser.
-
jQuery — Use this to handle user interactions and DOM manipulation.
-
Font Awesome — For nice icons like arrows and zoom buttons.
Here’s the HTML file setup:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>PDF Viewer in jQuery</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" /> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <link rel="stylesheet" href="style.css" /> </head> <body> <header> <ul class="navigation"> <li class="navigation__item"> <a href="#" class="previous round" id="prev_page"> <i class="fas fa-arrow-left"></i> </a> <input type="number" value="1" id="current_page" /> <a href="#" class="next round" id="next_page"> <i class="fas fa-arrow-right"></i> </a> Page <span id="page_num">1</span> of <span id="page_count">1</span> </li> <li class="navigation__item"> <button class="zoom" id="zoom_in"> <i class="fas fa-search-plus"></i> </button> <button class="zoom" id="zoom_out"> <i class="fas fa-search-minus"></i> </button> </li> <li class="navigation__item"> <button class="print-button"> <i class="fa-solid fa-print"></i> </button> </li> </ul> </header> <canvas id="canvas" class="canvas__container"></canvas> <script type="module" src="index.js"></script> </body> </html>
Core features of the PDF viewer
This PDF viewer comes with several key features:
-
Navigation — Move between pages with Next and Previous buttons.
-
Zoom — Zoom in and out of the PDF pages.
-
Page jumping — Jump directly to a specific page by typing the page number.
-
Printing — Print the PDF document directly from the viewer.
JavaScript logic for the PDF viewer
Now, examine the JavaScript code that powers the PDF rendering and interaction:
const pdf = 'document.pdf'; // Import necessary modules from PDF.js. import { GlobalWorkerOptions, getDocument, } from 'https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.min.mjs'; // Set the worker source to the PDF.js worker. GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.worker.min.mjs'; const initialState = { pdfDoc: null, // PDF document object. currentPage: 1, // Current page number. pageCount: 0, // Total number of pages. zoom: 1, // Current zoom level. }; // Render the current page to the canvas. const renderPage = () => { initialState.pdfDoc .getPage(initialState.currentPage) .then((page) => { const canvas = $('#canvas')[0]; // Get canvas element. const ctx = canvas.getContext('2d'); // Get canvas context. const viewport = page.getViewport({ scale: initialState.zoom, }); canvas.height = viewport.height; // Set canvas height. canvas.width = viewport.width; // Set canvas width. // Render the PDF page into the canvas. const renderCtx = { canvasContext: ctx, viewport: viewport, }; page.render(renderCtx); // Update the page number on the UI. $('#page_num').text(initialState.currentPage); }); }; // Load the PDF document. getDocument(pdf) .promise.then((data) => { initialState.pdfDoc = data; // Save the PDF document. $('#page_count').text(initialState.pdfDoc.numPages); // Display total page count. renderPage(); // Render the first page. }) .catch((err) => { alert(err.message); // Handle error if PDF fails to load. });
Key sections:
-
Loading the PDF:
-
The
getDocument
function from PDF.js loads the PDF. You specify the file (in this case,document.pdf
). -
The
promise
function ensures the PDF is loaded before performing any operations.
-
-
Rendering pages:
-
The
renderPage()
function renders the current page on a canvas. -
Use
getViewport()
to adjust the zoom level and scale the page accordingly. -
The
canvasContext
renders the content of the PDF page onto thecanvas
element on the webpage.
-
Adding navigation and zoom controls
Now, take a look at the jQuery logic for handling navigation and zoom controls:
// Show Previous Page. const showPrevPage = () => { if (initialState.pdfDoc === null || initialState.currentPage <= 1) return; initialState.currentPage--; $('#current_page').val(initialState.currentPage); // Update current page input. renderPage(); // Render the previous page. }; // Show Next Page. const showNextPage = () => { if ( initialState.pdfDoc === null || initialState.currentPage >= initialState.pdfDoc.numPages ) return; initialState.currentPage++; $('#current_page').val(initialState.currentPage); // Update current page input. renderPage(); // Render the next page. }; // Zoom In. const zoomIn = () => { if (initialState.pdfDoc === null) return; initialState.zoom *= 1.25; // Increase the zoom factor. renderPage(); // Rerender the current page with updated zoom. }; // Zoom Out. const zoomOut = () => { if (initialState.pdfDoc === null) return; initialState.zoom *= 0.8; // Decrease the zoom factor. renderPage(); // Rerender the current page with updated zoom. };
-
Navigation —
showPrevPage()
andshowNextPage()
update thecurrentPage
variable and rerender the page. -
Zoom —
zoomIn()
andzoomOut()
adjust the zoom factor (initialState.zoom
) and re-render the page at the new zoom level.
Adding event listeners with jQuery
Now, you need to handle the events triggered by the user:
// Bind events using jQuery. $('#prev_page').on('click', showPrevPage); $('#next_page').on('click', showNextPage); $('#zoom_in').on('click', zoomIn); $('#zoom_out').on('click', zoomOut); // Keypress Event for jumping to a page. $('#current_page').on('keypress', (event) => { if (initialState.pdfDoc === null) return; if (event.keyCode === 13) { let desiredPage = parseInt($('#current_page').val()); initialState.currentPage = Math.min( Math.max(desiredPage, 1), initialState.pdfDoc.numPages, ); $('#current_page').val(initialState.currentPage); renderPage(); } }); // Optional Print Support. $('.print-button').on('click', () => { window.print(); });
-
Event bindings — jQuery is used to bind click events to the buttons. Each event handler corresponds to a specific function (e.g.
showPrevPage
,zoomIn
). -
Keypress for jumping pages — If the user types a number in the
input
field and presses Enter, the page jumps to the desired page.
Challenges of working with PDF.js
PDF.js is an open source library that provides basic PDF viewing functionality right out of the box. However, it has some limitations that can become apparent when working with more advanced use cases or large, complex documents.
- Limited documentation and an unstructured API design, leading to longer development times when customizing the PDF.js viewer.
- Significant time and developer resources are required to add advanced features — like annotations, document editing, and eSignatures — to the viewer.
- Performance issues with large or complex PDFs, leading to slow rendering and poor user experience. Handling large documents or highly detailed PDFs often leads to performance bottlenecks.
- Challenges in maintaining and fixing the viewer when a new version of PDF.js is released, often requiring additional development work.
Benefits of Nutrient for PDF viewing and annotations
While PDF.js is a great tool for basic PDF rendering, Nutrient offers many advanced features out of the box, designed to meet the needs of businesses and teams that require a robust PDF viewer and editor. Nutrient’s powerful features make it ideal for industries like legal, education, and finance, where document collaboration and annotations are critical.
- Save time with a well-documented API, making it easier to customize the UI to your specific requirements. This ensures smoother development cycles and quicker product releases.
- Utilize 15+ prebuilt annotation tools for drawing, circling, highlighting, commenting, and adding notes to documents. These features are particularly beneficial for industries like legal and education, where collaboration and feedback are essential.
- View PNG, JPG, TIFF, and MS Office documents directly on the client side without needing server deployment. This allows seamless integration into existing workflows that require different file formats.
- Easily add features like PDF editing, digital signatures, form filling, real-time document collaboration, and more, streamlining workflows for teams, and increasing productivity.
- Benefit from enterprise-level support, with dedicated engineers available to help with implementation, ensuring fast resolution of any issues and offering a more reliable experience for businesses.
- Nutrient offers seamless integration with various platforms, making it a versatile solution for different tech stacks.
Code snippets and setup
Getting started with Nutrient for jQuery is straightforward. This tutorial will guide you through the setup process — from installing the library, to embedding the PDF viewer into your project.
-
Install the Nutrient library with
npm
:
npm install pspdfkit
yarn add pspdfkit
-
Copy the necessary library files to your
assets
directory for the viewer to function correctly:
cp -R ./node_modules/pspdfkit/dist/ ./assets/
Ensure your assets
directory contains the pspdfkit.js
file and the necessary library assets for smooth integration.
Integrating Nutrient into your project
-
Add the PDF document you want to display to your project’s directory. You can use the demo document as an example.
-
Create an empty
<div>
element for the PDF viewer:
<div id="pspdfkit" style="width: 100%; height: 100vh;"></div>
-
Include the jQuery CDN in your HTML:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
-
Load
pspdfkit.js
:
<script src="assets/pspdfkit.js"></script>
-
Initialize Nutrient Web SDK:
<script> PSPDFKit.load({ container: '#pspdfkit', document: 'document.pdf', }) .then(function (instance) { console.log('PSPDFKit loaded', instance); }) .catch(function (error) { console.error(error.message); }); </script>
Serving the website locally
Another option is to use the serve
package as a simple HTTP server. Follow the steps below if you want to use that option.
-
Install the serve package:
npm install --global serve
yarn global add serve
-
Serve the contents of the current directory:
serve -l 8080 .
Navigate to http://localhost:8080 to view the website.
If you want to download Nutrient manually or integrate it as a module, you can check out our jQuery getting started guide.
Visual comparison: PDF.js vs. Nutrient
Here’s a side-by-side comparison of the features of PDF.js vs. Nutrient:
Feature | PDF.js | Nutrient |
---|---|---|
Basic PDF viewing | ✔️ Simple PDF rendering | ✔️ Advanced rendering with better performance for large files |
Annotations | ❌ Limited or requires extensive custom development | ✔️ 15+ built-in annotation tools for legal, educational, and business use |
Document editing | ❌ Not supported out of the box | ✔️ Full editing, form filling, and digital signature capabilities |
Performance | ❌ Slower performance with large PDFs | ✔️ High performance even with large and complex documents |
Support | ❌ Community support only | ✔️ Enterprise-grade support with dedicated engineers |
Integration | ✔️ Easy to integrate with basic projects | ✔️ Seamless integration with various tech stacks and platforms |
Conclusion
PDF.js is a fantastic lightweight, open source solution for simple PDF rendering needs. It’s an excellent choice for projects where basic PDF viewing functionality is sufficient, and there are no performance or complex interaction requirements. However, if you need more advanced features like annotations, document editing, real-time collaboration, or enterprise-level support, Nutrient stands out as a powerful solution.
In this tutorial, we explored how to build a PDF viewer with both PDF.js and Nutrient. While PDF.js is suitable for smaller projects or those with basic needs, Nutrient’s advanced features and enterprise support make it the ideal choice for larger projects where enhanced functionality and performance are essential.
We’ve also created similar tutorials for various web frameworks and libraries:
- How to build an Angular PDF viewer with PDF.js
- How to build a Vue.js PDF viewer with PDF.js
- How to build a React PDF viewer with PDF.js
- How to build a Bootstrap 5 PDF viewer with PDF.js
- How to build an Electron PDF viewer with PDF.js
- How to build a TypeScript PDF viewer with PDF.js
- How to build a JavaScript PDF viewer with PDF.js
To get started with our jQuery PDF viewer, try it for free, or launch our web demo.
FAQ
Here are a few frequently asked questions about PDF.js and Nutrient.
What is the main difference between PDF.js and Nutrient?
PDF.js is an open source JavaScript library focused on rendering PDFs in the browser, while Nutrient offers a commercial PDF SDK with more features like annotations, form filling, and OCR.
Can I add annotations to PDFs using both PDF.js and Nutrient?
Yes, both libraries support annotations, but Nutrient provides a more extensive set of tools and customization options for annotations.
Is it possible to handle large PDFs with both PDF.js and Nutrient?
Yes, both libraries can handle large PDFs, but Nutrient has optimizations for better performance with larger files and complex documents.
How customizable are the PDF.js and Nutrient viewers?
Both viewers can be customized, but Nutrient offers more flexibility for custom UI elements and tools, especially in enterprise applications.
Can I use Nutrient and PDF.js in frameworks like Angular or React?
Yes, both libraries are compatible with popular JavaScript frameworks, though integration approaches may vary depending on project requirements.