Using WebPDF

WebPDF is two custom elements: <pdf-file> loads a PDF document, and <pdf-page> shows one of its pages. This article shows how to add them to a web page, load files into them, and work with them from JavaScript.

Loading WebPDF

Add the WebPDF <script> to your page once, as a module:

html
<script src=//new.webpdf.pro/.js type=module></script>

The script defines <pdf-file> and <pdf-page>. You can write the elements anywhere in the document, before or after the script: like every custom element, they are upgraded when their definition arrives. Attributes on the script itself set defaults for every file and page; see Multi-homed attributes.

Note: WebPDF reads its settings from a module script whose src contains webpdf, such as the one above. Keep both when you copy it.

Showing a page

A <pdf-file> loads a document and draws nothing itself. A <pdf-page> shows one page of the file whose id its of attribute names:

The first page of a PDF

html
<pdf-file id=f src=//pdf.ist/web.pdf></pdf-file>
<pdf-page of=f scale=0.5></pdf-page>

The page is not just a picture of the page: you can select its text, find words in it with the browser's find, follow its links and fill its form fields.

Choosing the page

The no attribute picks the page: 1 (the default) is the first one. Negative numbers count from the end, so -1 is the last page, whatever the file's length:

html
<pdf-page of=f no=2></pdf-page>
<pdf-page of=f no=-1></pdf-page>

Numbers past either end show the first or the last page; see PDFPageElement.no.

Many pages, one file

One file serves any number of pages, and a page nested in a file shows that file without an of attribute. The file holds the document once, so its pages share one download, and form fields stay in sync across them:

html
<pdf-file src=//pdf.ist/web.pdf>
  <pdf-page no=1></pdf-page>
  <pdf-page no=2></pdf-page>
</pdf-file>

A file is laid out as if it were not there (display: contents), so the pages inside it sit in the layout of its parent.

Sizing the page

A page is sized like an image. At scale 1, its box has the page's own size, one PDF point being 96 / 72 CSS pixels, so an A4 page is about 794 × 1123 pixels. Other scales multiply that size; or you size the page with CSS, like an <img>, and scale only sets how sharp it is drawn. The page keeps its aspect ratio either way. See Styling WebPDF.

Loading files

The file's src attribute takes any URL: absolute, relative, data: or blob:. Changing it loads the new document, and every page follows:

js
const file = document.querySelector("pdf-file");
file.src = "report.pdf";

load() does the same, and also takes bytes, a Blob, a File or a FileSystemFileHandle. It returns a promise, so you know when the file is ready:

js
try {
  await file.load("//new.webpdf.pro/forms.pdf");
} catch (error) {
  console.error(error); // a PDFLoadError
}

open() asks the user for a file instead, and every page is a drop target: drop a PDF, its form data, or a link to a PDF onto a page, and its file loads it. See Saving and exporting.

Files from other sites

A PDF from another origin needs CORS headers. When a direct fetch fails, the file tries once more through WebPDF's proxy, so most public PDFs load anyway; load() and the events wait for that retry. proxy lets you route a file through your own proxy instead.

Encrypted files

Give an encrypted PDF its password with the password attribute; changing the password loads the file again.

Working with pages from JavaScript

Every attribute has a property, so you can drive pages from your own interface. Here two buttons turn the pages of a <pdf-page>, and its render event tells the page number:

Turning pages with your own buttons

html
<pdf-file id=f src=//pdf.ist/web.pdf></pdf-file>
<p>
  <button id=prev>Previous</button>
  <button id=next>Next</button>
  <output id=out></output>
</p>
<pdf-page id=page of=f scale=0.4></pdf-page>
js
const page = document.querySelector("#page");
document.querySelector("#prev").addEventListener("click", () => page.no--);
document.querySelector("#next").addEventListener("click", () => page.no++);
page.addEventListener("render", () => {
  document.querySelector("#out").value = `Page ${page.no} of ${page.file.js.numPages}`;
});

Or let the page be a viewer of its own: with controls, it gets keys, a bar and touch gestures, like a <video controls>. See Viewer controls.

Events

WebPDF elements fire these events. Listen to them with addEventListener(): there are no on… event handler properties.

EventFired atWhen
load<pdf-file>The PDF has loaded, also after every reload.
error<pdf-file>The PDF or its form data failed to load, also through the proxy.
verify<pdf-file>The signatures have been checked.
load<pdf-page>The page knows its size, before it draws.
render<pdf-page>The page has drawn.
error<pdf-page>The page has no file, or could not be drawn.
signature<pdf-page>Someone clicked a signature. Cancelable.

They are all CustomEvent objects that bubble, and they are composed, so they reach listeners outside a shadow root unless you set composed to false. A page's events bubble through a file it is nested in, so check event.target when you listen on a file, or give both kinds of event their own names with event:prefix=type:

html
<script src=//new.webpdf.pro/.js type=module event:prefix=type></script>
js
document.addEventListener("pdf-file-load", (event) => console.log("file", event.target.name));
document.addEventListener("pdf-page-render", (event) => console.log("page", event.target.no));

Browser support

WebPDF works in the browsers its PDF.js build supports. WebPDF always loads the latest PDF.js, version 6.4 as of October 2026, which supports:

Each of these versions also has every platform feature WebPDF itself needs: custom elements and closed shadow roots, custom states (:state()), CSS nesting, light-dark(), popovers and Promise.withResolvers(). That is why the compatibility tables in these docs show the same versions for every feature. Since July 2026, when Firefox 153 came out, these are the current versions of every major browser.

A few features need more, and the tables say so in a note:

WebPDF also runs in apps, through their web views: WebView2 on Windows, WebView on Android and WKWebView on macOS and iOS.

Note: When PDF.js raises its targets, for example when a new Firefox ESR comes out, these versions move with it.

See also