webdevpuneet.com

PDF.js Viewer with Thumbnails, Zoom and Rotate — Free JavaScript Snippet

PDF.js Viewer with Thumbnails, Zoom and Rotate · Media · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="pv">
  <div class="pv-toolbar" role="toolbar" aria-label="PDF controls">
    <label class="pv-open">Open PDF<input type="file" id="pvFile" accept="application/pdf"></label>
    <span class="pv-sep"></span>
    <button type="button" id="pvPrev" aria-label="Previous page">‹</button>
    <label class="pv-page"><input id="pvNum" type="number" min="1" value="1" aria-label="Page number"> / <span id="pvCount">–</span></label>
    <button type="button" id="pvNext" aria-label="Next page">›</button>
    <span class="pv-sep"></span>
    <button type="button" id="pvOut" aria-label="Zoom out">−</button>
    <select id="pvZoom" aria-label="Zoom level">
      <option value="fit">Fit width</option><option value="0.5">50%</option><option value="0.75">75%</option>
      <option value="1">100%</option><option value="1.25">125%</option><option value="1.5">150%</option><option value="2">200%</option>
    </select>
    <button type="button" id="pvIn" aria-label="Zoom in">+</button>
    <button type="button" id="pvRot" aria-label="Rotate 90 degrees">⟳</button>
    <span class="pv-name" id="pvName"></span>
  </div>
  <div class="pv-body">
    <nav class="pv-thumbs" id="pvThumbs" aria-label="Page thumbnails"></nav>
    <div class="pv-stage" id="pvStage" tabindex="0" aria-label="Page view"><canvas id="pvCanvas"></canvas></div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

PDF.js rendering
Mozilla's engine, no native viewer.
Thumbnail sidebar
Click to jump; current page highlighted.
Page navigation
Buttons, page input and keyboard.
Zoom presets and fit width
Rotation-aware fitting.
Rotation
90° steps via viewport rotation.
High-DPI output
Rendered at devicePixelRatio.
Render cancellation
No garbled pages from overlapping renders.
Local file opening
Private, with error handling.

About this UI Snippet

Build Your Own PDF Viewer With PDF.js — Thumbnails, Zoom and Rotation

Screenshot of the PDF.js Viewer with Thumbnails, Zoom and Rotate snippet rendered live

Browsers can show PDFs natively, but an embedded native viewer can't be styled, controlled or integrated with the rest of your UI. PDF.js — the engine behind Firefox's built-in viewer — gives you the rendering and leaves the interface to you. This snippet builds a compact viewer with the controls people expect.

Load, get a page, render to canvas

pdfjsLib.getDocument({ data }) parses the file and resolves to a document. getPage(n) returns a page, getViewport({ scale, rotation }) computes its size and transform, and page.render({ canvasContext, viewport }) draws it onto a canvas. Everything else in a viewer is state around those calls: current page, zoom level and rotation.

Sharp on high-DPI screens

The canvas is rendered at scale × devicePixelRatio and then shrunk back with CSS width and height, so text stays crisp on Retina and 4K displays instead of looking blurry.

Fit width, including rotated pages

Fit width divides the available stage width by the page's width at scale 1 — measured *with the current rotation*, because a rotated portrait page is as wide as it was tall. The sample includes a landscape page to show mixed orientations.

Cancel before re-rendering

Clicking zoom twice quickly would start two renders on the same canvas and produce a corrupted page. The snippet keeps the current renderTask, cancels it, waits for it to settle, then starts the new render; the RenderingCancelledException from a cancelled task is expected and ignored.

Thumbnails

Every page is also rendered into a small canvas in the sidebar. Clicking one jumps to it, and the current page is marked with aria-current="page" and scrolled into view.

Private file opening

Opening a local file reads it with the File API; nothing is uploaded. A generated five-page sample is shown on load.

Step by step

How to Use

  1. 1
    Browse the sampleA five-page document opens with thumbnails on the left.
  2. 2
    NavigateUse ‹ ›, type a page number, click a thumbnail, or arrow keys on the page.
  3. 3
    ZoomFit width, preset levels, or + and − (buttons or keys).
  4. 4
    Rotate⟳ turns the page 90° at a time; fit width adjusts.
  5. 5
    Open your own PDFIt's read locally and never uploaded.

Real-world uses

Common Use Cases

Document portals
Show invoices, contracts or reports inside your own interface, with a thumbnail sidebar that highlights the current page and jumps on click.
E-learning handouts
Display course materials in the lesson page itself, with page-number input, buttons and keyboard shortcuts for navigation.
Review and approval tools
Use as the base for annotation workflows, since PDF.js rendering leaves the surrounding controls entirely under your control.
Generated PDF previews
Preview a generated document before sending it, using rotation-aware fit-width zoom and high-DPI rendering for crisp text.
PDF.js API reference
Learn the essentials in one file, including safe render task handling so rapid page changes do not produce overlapping draws.
Related: PDF.js Text Search
Related: jsPDF Invoice Generator

Got questions?

Frequently Asked Questions

Load the document with pdfjsLib.getDocument({ url }) or ({ data }), get a page with getPage(n), create a viewport with getViewport({ scale }), size a canvas to the viewport and call page.render({ canvasContext, viewport }).

The canvas is being drawn at CSS pixel size on a high-DPI screen. Render at scale × window.devicePixelRatio and set the canvas's CSS width and height to the unscaled size.

Pass rotation (0, 90, 180 or 270) to getViewport. Remember that width and height swap at 90 and 270 degrees when calculating fit-to-width.

Two renders are drawing into the same canvas. Keep the render task, call cancel() on it before starting a new render, and ignore the RenderingCancelledException it rejects with.

PDF.js 3.x ships a classic pdf.min.js that defines window.pdfjsLib. Version 4 and later are ES modules, which you load with a module script or a bundler.