Skip to content

Commit 695dca9

Browse files
committed
Update pdfjs-viewer attributes and documentation for clarity and accuracy
1 parent de97ac7 commit 695dca9

4 files changed

Lines changed: 82 additions & 38 deletions

File tree

‎eleventy.config.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default function (eleventyConfig) {
6767
<th scope="row"><a href="#attr-${attr.name}"><code>${attr.name}</code></a></th>
6868
<td>${inline(attr.description)}</td>
6969
<td class="default">${attr.default ? inline(attr.default) : `<span class="muted"><span aria-hidden="true">—</span><span class="visually-hidden">None</span></span>`}</td>
70-
<td><span class="update update-${attr.update}">${{ live: "Live", load: "Next load", init: "Before connect" }[attr.update]}</span></td>
70+
<td><span class="update update-${attr.update}">${{ live: "Live", load: "Next load", init: "Before connect", none: "No effect" }[attr.update]}</span></td>
7171
</tr>`
7272
)
7373
.join("");

‎src/_data/pdfjsAttributes.js‎

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Attributes of <pdfjs-viewer-element>, rendered as the reference tables and the playground.
22
// `update`: live = applies immediately, load = applies to the next document load,
3-
// init = read only when the viewer is built, so set it before the element is connected.
3+
// init = read only when the viewer is built, so set it before the element is connected,
4+
// none = has no effect.
45
const samples = "/pdfjs-viewer/samples/";
56

67
export default [
@@ -75,9 +76,9 @@ export default [
7576
{
7677
name: "locale-src-template",
7778
group: "interface",
78-
description: "URL of the locale file, with a `{locale}` placeholder. Use it to self-host locales.",
79+
description: "Absolute URL of the locale file, with a `{locale}` placeholder. Use it to self-host locales. Read when the viewer is built and when `locale` changes.",
7980
default: "`https://cdn.jsdelivr.net/gh/mozilla-l10n/firefox-l10n@main/{locale}/toolkit/toolkit/pdfviewer/viewer.ftl`",
80-
update: "load",
81+
update: "init",
8182
},
8283
{
8384
name: "iframe-title",
@@ -131,37 +132,37 @@ export default [
131132
{
132133
name: "c-map-url",
133134
group: "resources",
134-
description: "Folder of CMaps, needed for some CJK text.",
135+
description: "Absolute URL of the CMaps folder, ending in `/`. Needed for some CJK text.",
135136
default: "`../web/cmaps/`",
136137
update: "load",
137138
},
138139
{
139140
name: "standard-font-data-url",
140141
group: "resources",
141-
description: "Folder of the standard fonts, for PDFs that use non-embedded base fonts.",
142+
description: "Absolute URL of the standard fonts folder, ending in `/`. For PDFs that use non-embedded base fonts.",
142143
default: "`../web/standard_fonts/`",
143144
update: "load",
144145
},
145146
{
146147
name: "wasm-url",
147148
group: "resources",
148-
description: "Folder of the WASM image decoders (JPEG 2000, JBIG2).",
149+
description: "Absolute URL of the WASM image decoders folder (JPEG 2000, JBIG2), ending in `/`.",
149150
default: "`../web/wasm/`",
150151
update: "load",
151152
},
152153
{
153154
name: "icc-url",
154155
group: "resources",
155-
description: "Folder of ICC color profiles.",
156+
description: "Absolute URL of the ICC color profiles folder, ending in `/`.",
156157
default: "`../web/iccs/`",
157158
update: "load",
158159
},
159160
{
160161
name: "image-resources-path",
161162
group: "resources",
162-
description: "Folder of annotation icons (`annotation-*.svg`). Shipped in the package as `dist/images/`.",
163+
description: "Folder of annotation icons (`annotation-*.svg`), shipped in the package as `dist/images/`. The default is relative to your page, so set this or `assets-base`.",
163164
default: "`./images/`, or `assets-base` + `images/`",
164-
update: "load",
165+
update: "init",
165166
},
166167
{
167168
name: "sandbox-bundle-src",
@@ -173,8 +174,8 @@ export default [
173174
{
174175
name: "debugger-src",
175176
group: "resources",
176-
description: "PDF.js debugger script URL.",
177+
description: "PDF.js debugger script URL. It has no effect: the debugger isn't shipped in the package, and the element offers no way to turn it on.",
177178
default: "`./debugger.mjs`",
178-
update: "load",
179+
update: "none",
179180
},
180181
];

‎src/pdfjs-viewer/docs.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const ELEMENT_URL = '/pdfjs-viewer/vendor/pdfjs-viewer-element.js'
55
const BASE_ATTRIBUTES = {
66
src: '/pdfjs-viewer/samples/sample-pdf-with-images.pdf',
77
'iframe-title': 'Live preview of the documented PDF viewer',
8+
'image-resources-path': '/pdfjs-viewer/vendor/images/',
89
}
910
// Placeholder used in snippets where the file doesn't matter; Try keeps the current document.
1011
const PLACEHOLDER_SRC = '/file.pdf'

‎src/pdfjs-viewer/index.md‎

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: pdfjs-viewer · PDF viewer web component
44
description: Docs for @missing-elements/pdfjs-viewer, a self-hostable PDF viewer web component based on the PDF.js default viewer. Install, attributes, API, theming, hosting and framework guides.
55
---
66

7-
The full PDF.js viewer as one HTML element. It runs in an isolated iframe and has no runtime dependencies. PDF.js and its worker ship inside the package, so nothing loads from a CDN unless you choose to. Each **Try** button applies its example to the live preview, and **Reset** puts the preview back to its defaults.
7+
The full PDF.js viewer as one HTML element. It runs in an isolated iframe and has no runtime dependencies. PDF.js and its worker ship inside the package, so by default nothing loads from a CDN. The one exception is locale files, which come from jsDelivr when you set `locale`. Each **Try** button applies its example to the live preview, and **Reset** puts the preview back to its defaults.
88

99
## Quick start
1010

@@ -45,7 +45,7 @@ viewer.setAttribute('zoom', 'page-fit')
4545

4646
The **Updates** column in the tables below says when a change takes effect:
4747

48-
- **Live**: immediately. Changing `src` opens the new file without rebuilding the viewer. `page`, `zoom`, `pagemode`, `search` and `phrase` are applied together, so changing any of them also goes to the page in `page`, or to page 1 when `page` is unset.
48+
- **Live**: immediately. Changing `src` opens the new file without rebuilding the viewer. `page`, `zoom`, `pagemode`, `search` and `phrase` are applied together. Changing any of them also goes to the page in `page` (page 1 when it's unset) and resets the sidebar to `pagemode`, closing a sidebar the reader opened.
4949
- **Next load**: with the next document the viewer opens.
5050
- **Before connect**: read once, when the viewer is built. Set it before you add the element to the page.
5151

@@ -78,7 +78,7 @@ You rarely need these. See [Hosting](#hosting).
7878

7979
### PDF.js resources
8080

81-
Data that only some PDFs need. The package doesn't include it, so see [PDF.js resources](#cmaps-fonts-and-other-resources) before you set these.
81+
Data that only some PDFs need. The package doesn't include it, and the defaults are relative paths that don't work inside the viewer. See [PDF.js resources](#cmaps-fonts-and-other-resources) before you set these.
8282

8383
{% attributeTable "resources" %}
8484

@@ -109,7 +109,7 @@ await viewer.setViewerOptions({
109109
})
110110
```
111111

112-
The options are applied while the viewer is being built, so call this right after you add the element. A call made after `initPromise` has resolved has no effect until the viewer rebuilds. Each call replaces the options of the previous one. It resolves to `{ viewerOptions }` once the viewer is ready.
112+
The options are applied while the viewer is being built, so call this right after you add the element. A call made after `initPromise` has resolved has no effect until the viewer rebuilds. Each call replaces the options of the previous one, and the options are cleared once applied. A rebuild (a `locale` change that can't be applied in place, or moving the element to another place in the page) drops them, so call it again after one. It resolves to `{ viewerOptions }` once the viewer is ready.
113113

114114
### `injectViewerStyles(css)`
115115

@@ -150,7 +150,7 @@ The default Paper & Ink theme follows the system color scheme. To force one sche
150150

151151
### Your own colors
152152

153-
The viewer is styled with CSS custom properties. To restyle it, override them with `injectViewerStyles`. Paper & Ink sets its palettes on `:root`, and on `:root[data-color-scheme]` when a scheme is forced, so target both selectors. Any variable you don't override keeps the current scheme's value, so pair a custom palette with a fixed `viewer-css-theme`:
153+
The viewer is styled with CSS custom properties. To restyle it, override them with `injectViewerStyles`. Paper & Ink sets its palette on `:root`, and on `:root[data-color-scheme=dark]` when dark is forced, so target both selectors. Any variable you don't override keeps the current scheme's value, so pair a custom palette with a fixed `viewer-css-theme`:
154154

155155
```js try
156156
const viewer = document.querySelector('pdfjs-viewer-element')
@@ -193,15 +193,15 @@ The interface is in English unless you set `locale`. The locale file is download
193193

194194
Right-to-left locales such as `ar` and `he` also switch the layout direction.
195195

196-
> **Known issue in v{{ pdfjsViewer.version }}:** codes with a region, such as `pt-BR`, `zh-CN`, `es-ES` and `sv-SE`, don't load and the viewer stays in English. Language-only codes work.
196+
> **Known issue in v{{ pdfjsViewer.version }}:** codes are checked against a lowercase list, so codes with a region, such as `pt-BR`, `zh-CN`, `es-ES` and `sv-SE`, are ignored and the viewer stays in English. These languages have no language-only code to fall back on. As a workaround, use the lowercase code, such as `pt-br`, with a self-hosted `locale-src-template` that uses the same lowercase folder name.
197197
198-
To serve locale files yourself, which is useful under a strict CSP or when you can't rely on third parties, copy them from [mozilla-l10n/firefox-l10n](https://github.com/mozilla-l10n/firefox-l10n) (`<locale>/toolkit/toolkit/pdfviewer/viewer.ftl`) and point `locale-src-template` at them:
198+
To serve locale files yourself, which is useful under a strict CSP or when you can't rely on third parties, copy them from [mozilla-l10n/firefox-l10n](https://github.com/mozilla-l10n/firefox-l10n) (`<locale>/toolkit/toolkit/pdfviewer/viewer.ftl`) and point `locale-src-template` at them. The template must be an absolute URL: a relative one breaks all of the viewer's interface text.
199199

200200
```html
201201
<pdfjs-viewer-element
202202
src="/file.pdf"
203203
locale="de"
204-
locale-src-template="/locales/{locale}/viewer.ftl">
204+
locale-src-template="https://example.com/locales/{locale}/viewer.ftl">
205205
</pdfjs-viewer-element>
206206
```
207207

@@ -211,9 +211,9 @@ The element loads the viewer at runtime from five files next to `pdfjs-viewer-el
211211

212212
### Bundlers and `assets-base`
213213

214-
**Vite, Rollup and webpack 5** need no configuration. The element references its files as `new URL('./file', import.meta.url)`, so these bundlers emit them as assets and rewrite the URLs.
214+
**Vite and webpack 5** need no configuration. The element references its files as `new URL('./file', import.meta.url)`, so these bundlers emit them as assets and rewrite the URLs.
215215

216-
**esbuild and other bundlers** that don't understand that pattern move the element into your bundle without the files, and the viewer fails with 404s. Serve the package's `dist` folder as static files and point `assets-base` at it:
216+
**esbuild, plain Rollup and other bundlers** that don't handle that pattern move the element into your bundle without the files, and the viewer fails with 404s. Serve the package's `dist` folder as static files and point `assets-base` at it:
217217

218218
```html
219219
<pdfjs-viewer-element src="/file.pdf" assets-base="/static/pdfjs-viewer/">
@@ -231,6 +231,8 @@ The same attribute can load the files from a CDN:
231231

232232
`assets-base` is read when the viewer is built, so set it before the element is connected. A per-file attribute such as `worker-src` overrides it for that file.
233233

234+
Annotation icons need this whichever bundler you use. PDF.js loads them by name at runtime (`annotation-<name>.svg`), so no bundler emits them, and the default path is relative to your page. Serve the package's `dist/images` folder and point `image-resources-path` at it, or set `assets-base`, which covers the icons too.
235+
234236
### Static pipelines with hashed file names
235237

236238
If your pipeline renames files, for example with content hashes, set each runtime file URL instead of `assets-base`:
@@ -247,11 +249,13 @@ If your pipeline renames files, for example with content hashes, set each runtim
247249
</pdfjs-viewer-element>
248250
```
249251

250-
Annotation icons are loaded by name (`annotation-<name>.svg`), so keep the `dist/images` folder unhashed and point `image-resources-path` at it.
252+
Keep the `dist/images` folder unhashed: annotation icons are loaded by name.
251253

252254
### Worker
253255

254-
By default the worker is the bundled `pdf.worker.min.mjs`, served from your own origin. That works under a strict `script-src 'self'` policy. Set `worker-src` only to serve it from somewhere else, and use the matching PDF.js version ({{ pdfjsViewer.pdfjsVersion }}). A mismatch stops the viewer with an "API version does not match Worker version" error.
256+
By default the worker is the bundled `pdf.worker.min.mjs`, served from your own origin. PDF.js starts it from a `blob:` URL, so if your page has a Content Security Policy, allow `worker-src 'self' blob:`. Without that, PDF.js falls back to running on the main thread, which works but is slower.
257+
258+
Set `worker-src` only to serve the worker from somewhere else, and use the matching PDF.js version ({{ pdfjsViewer.pdfjsVersion }}). A mismatch stops the viewer with the error `The API version "…" does not match the Worker version "…"`.
255259

256260
```html
257261
<pdfjs-viewer-element
@@ -262,18 +266,18 @@ By default the worker is the bundled `pdf.worker.min.mjs`, served from your own
262266

263267
### CMaps, fonts and other resources
264268

265-
Most PDFs render with just the package. Some need extra PDF.js data: CMaps for some CJK text, standard fonts for non-embedded base fonts, WASM decoders for JPEG 2000 and JBIG2 images, and the scripting sandbox for PDFs with JavaScript. The package doesn't include these, and the defaults point at paths that usually don't exist on your site.
269+
Most PDFs render with just the package. Some need extra PDF.js data: CMaps for some CJK text, standard fonts for non-embedded base fonts, WASM decoders for JPEG 2000 and JBIG2 images, and the scripting sandbox for PDFs with JavaScript. The package doesn't include these, and the defaults are relative paths that don't work inside the viewer.
266270

267-
If your documents need them, copy the folders from `pdfjs-dist@{{ pdfjsViewer.pdfjsVersion }}` into your static files and point the attributes at them:
271+
If your documents need them, copy the folders from `pdfjs-dist@{{ pdfjsViewer.pdfjsVersion }}` into your static files and point the attributes at them. Use absolute URLs that end in `/`. PDF.js fetches these folders from its worker, which runs from a `blob:` URL where relative paths don't resolve, and it rejects a folder URL without the trailing slash.
268272

269273
```html
270274
<pdfjs-viewer-element
271275
src="/file.pdf"
272-
c-map-url="/pdfjs/cmaps/"
273-
standard-font-data-url="/pdfjs/standard_fonts/"
274-
wasm-url="/pdfjs/wasm/"
275-
icc-url="/pdfjs/iccs/"
276-
sandbox-bundle-src="/pdfjs/build/pdf.sandbox.min.mjs">
276+
c-map-url="https://example.com/pdfjs/cmaps/"
277+
standard-font-data-url="https://example.com/pdfjs/standard_fonts/"
278+
wasm-url="https://example.com/pdfjs/wasm/"
279+
icc-url="https://example.com/pdfjs/iccs/"
280+
sandbox-bundle-src="https://example.com/pdfjs/build/pdf.sandbox.min.mjs">
277281
</pdfjs-viewer-element>
278282
```
279283

@@ -308,14 +312,22 @@ export function PdfViewer({ src }) {
308312
With TypeScript, declare the tag once:
309313

310314
```ts
315+
import type { HTMLAttributes, RefAttributes } from 'react'
311316
import type { PdfjsViewerElement } from '@missing-elements/pdfjs-viewer'
312317

318+
type PdfjsViewerAttribute =
319+
| 'src' | 'page' | 'zoom' | 'pagemode' | 'search' | 'phrase'
320+
| 'viewer-css-theme' | 'locale' | 'locale-src-template' | 'iframe-title'
321+
| 'assets-base' | 'worker-src' | 'pdfjs-lib-src' | 'viewer-src' | 'viewer-css-src' | 'theme-css-src'
322+
| 'c-map-url' | 'standard-font-data-url' | 'wasm-url' | 'icc-url'
323+
| 'image-resources-path' | 'sandbox-bundle-src' | 'debugger-src'
324+
313325
declare module 'react' {
314326
namespace JSX {
315327
interface IntrinsicElements {
316-
'pdfjs-viewer-element': React.HTMLAttributes<PdfjsViewerElement> &
317-
React.RefAttributes<PdfjsViewerElement> &
318-
Partial<Record<'src' | 'page' | 'zoom' | 'pagemode' | 'search' | 'locale' | 'viewer-css-theme' | 'iframe-title', string>>
328+
'pdfjs-viewer-element': HTMLAttributes<PdfjsViewerElement> &
329+
RefAttributes<PdfjsViewerElement> &
330+
Partial<Record<PdfjsViewerAttribute, string>>
319331
}
320332
}
321333
}
@@ -353,7 +365,23 @@ defineProps({ src: String })
353365
</template>
354366
```
355367

356-
In Nuxt, register the import in a client-only plugin (`plugins/pdfjs-viewer.client.js`).
368+
In Nuxt, set the same compiler option in `nuxt.config`, and import the package from a client-only plugin:
369+
370+
```js
371+
// nuxt.config.js
372+
export default defineNuxtConfig({
373+
vue: {
374+
compilerOptions: { isCustomElement: (tag) => tag === 'pdfjs-viewer-element' },
375+
},
376+
})
377+
```
378+
379+
```js
380+
// plugins/pdfjs-viewer.client.js
381+
export default defineNuxtPlugin(() => {
382+
import('@missing-elements/pdfjs-viewer')
383+
})
384+
```
357385

358386
[Vue example on CodePen](https://codepen.io/redrobot753/pen/JoRYqwN)
359387

@@ -424,7 +452,21 @@ npm uninstall pdfjs-viewer-element
424452
npm install @missing-elements/pdfjs-viewer
425453
```
426454

427-
Then replace `pdfjs-viewer-element` with `@missing-elements/pdfjs-viewer` in imports and CDN URLs. If you're coming from an older major version:
455+
Then update your imports and CDN URLs:
456+
457+
```js
458+
import '@missing-elements/pdfjs-viewer' // was: import 'pdfjs-viewer-element'
459+
```
460+
461+
```html
462+
<!-- was: https://cdn.jsdelivr.net/npm/pdfjs-viewer-element/dist/pdfjs-viewer-element.js -->
463+
<script type="module" src="https://cdn.jsdelivr.net/npm/@missing-elements/pdfjs-viewer@{{ pdfjsViewer.major }}/dist/pdfjs-viewer-element.js"></script>
464+
```
465+
466+
If you're coming from an older major version:
428467

429-
- **From 3.x:** remove `use-built-in-worker`. The bundled worker is now always the default, and `worker-src` overrides it.
430-
- **From 2.x:** PDF.js is now bundled, so remove `viewer-path` and your copy of the PDF.js prebuild. Replace `initialize()` with [`initPromise`](#initpromise), and `viewer-extra-styles` / `viewer-extra-styles-urls` with [`injectViewerStyles()`](#injectviewerstyles-css). The `nameddest`, `text-layer`, `disable-*` and `verbosity` attributes are gone. Their PDF.js equivalents (`disableRange`, `textLayerMode` and so on) can be set with [`setViewerOptions()`](#setvieweroptions-options).
468+
- **From 3.x:** version 4 moved from PDF.js 5 to PDF.js 6. If you set `worker-src`, point it at `pdfjs-dist@{{ pdfjsViewer.pdfjsVersion }}`. From 3.0.x, also replace `viewer-extra-styles` and `viewer-extra-styles-urls` with [`injectViewerStyles()`](#injectviewerstyles-css).
469+
- **From 2.x:** PDF.js is now bundled, so remove `viewer-path` and your copy of the PDF.js prebuild. Replace `initialize()` with [`initPromise`](#initpromise), and `viewer-extra-styles` and `viewer-extra-styles-urls` with [`injectViewerStyles()`](#injectviewerstyles-css). The `nameddest`, `text-layer`, `disable-*` and `verbosity` attributes are gone:
470+
- `disableRange`, `disableStream`, `disableAutoFetch`, `disableFontFace`, `textLayerMode` and `verbosity` can be set as PDF.js options with [`setViewerOptions()`](#setvieweroptions-options).
471+
- For a named destination, call `viewerApp.pdfLinkService.goToDestination(name)` after [`initPromise`](#initpromise) resolves.
472+
- `disable-worker` has no replacement.

0 commit comments

Comments
 (0)