Viewer controls

A <pdf-page> with the controls attribute is a viewer of its own, like a <video> with controls: you turn its pages, rotate and zoom it, switch its renderer, show it fullscreen, copy and save it. This article shows the three ways in, the keyboard, the bar and gestures, and how to tailor them.

Turning controls on

Add controls to a page, to a file for all its pages, or to the <script> for every page in the document. It is multi-homed, so a page can turn inherited controls off with controls=-:

A page with controls

Hover the page for its bar, or click it and use the keys.

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

The keyboard

The keys work while the page has focus: click it, or reach it with Tab. ⌘ works as Ctrl. Ctrl S and Ctrl O, with Alt for form data, work from anywhere inside every page, also without controls, and never reach the browser's own save and open.

KeysDoes
A or ←p.no--
D or →p.no++
Homep.no = 1 (-N when no is negative)
Endp.no = p.file.js.numPages (-1 when no is negative)
Alt ← or Alt →p.no-- or p.no++, round the ends (last → first, first → last)
Alt Endp.no = +Infinity
Ctrl ← or Ctrl →p.no = -1 or p.no = +1
Qp.rotation -= 90
Ep.rotation += 90
Sp.rotation += 180
Jp.canvas = '.js'; p.svg = false
Ip.canvas = 'ium'; p.svg = false
Vp.svg = true
Alt Vp.svg = !p.svg
Alt Tp.off.toggle('text')
Alt Ap.off.toggle('anno')
Alt Sp.signatures = !p.signatures
Alt Shift Sp.file.signatures = !p.file.signatures
F or F11await p.toggleFullscreen()
EscLeaves the page (or fullscreen).
Ctrl Cnavigator.clipboard.write([await p.image.export(ClipboardItem)])
Ctrl Dnavigator.clipboard.writeText(await p.image.export(URL))
Ctrl -p.scale -= 0.1
Ctrl 1p.scale = 1
Ctrl 2, 3 or 4p.scale = 2, 3 or 4
Ctrl +p.scale += 0.1
Ctrl Sp.file.save()
Ctrl Op.file.open()
Alt Ctrl Sp.file.XFDF.save()
Alt Ctrl Op.file.XFDF.open()

The bar

Hover a page with controls, or tap it, and a bar shows for a few seconds, and stays while you use it. It holds ‹ and › with the page number, ⟲ and ⟳, − % and +, ⛶, and ⋯ for a menu of everything else, each item with its key. The bar fits its page: on a small page, the buttons that do not fit move into the menu.

The bar sits on the bottom edge. toolbar moves it to another edge, top, left or right, and on the left or the right it stands upright. The logical edges block-start, block-end, inline-start and inline-end follow the page's direction: inline-start is the left edge, and the right one in a right-to-left page.

A bar on two other edges

html
<pdf-file id=f src=//pdf.ist/web.pdf controls></pdf-file>
<pdf-page of=f toolbar=top scale=0.3></pdf-page>
<pdf-page of=f toolbar=inline-start scale=0.3></pdf-page>

Hover each page to see its bar.

Leaving controls out

controlslist leaves controls out of the bar and its menu, like controlslist on a <video>. Its tokens are nopaging, norotation, noscale, nofullscreen, norenderer, nolayers, nosignatures, nocopy, nodownload and noopen; see PDFElement.controlsList. As with a video, the keys and gestures of a control left out keep working. Two more tokens go further: notoolbar leaves out the whole bar, and nogestures turns the gestures off; the keys always work.

html
<pdf-page of=f controls controlslist="norenderer nocopy nodownload noopen"></pdf-page>
<pdf-page of=f controls controlslist=notoolbar></pdf-page>   <!-- keys and gestures only -->

To take a feature away completely, turn it off instead: -=drop stops dropping files on the page, and the break tokens on the script turn off fullscreen and other built-in behaviors.

Mouse and touch

InputDoes
🖱️ The mouse over the page, or 👆 a tapShows the bar for 2 seconds; it stays while you use it. A second tap hides it.
‹ or › (˄ or ˅ on an upright bar)p.no-- or p.no++
The page number, then Enterp.no = n; a negative number counts from the end, and Esc reverts
⟲ or ⟳p.rotation -= 90 or p.rotation += 90
− , % or +p.scale -= 0.1, p.scale = 1 or p.scale += 0.1, from 0.1 to 8
⛶await p.toggleFullscreen()
⋯The menu: the other keys, each with its shortcut
👆 A swipe ← or →p.no++ or p.no-- (mirrored right to left)
👆 Two fingers twisted ↻ or ↺p.rotation += 90 or p.rotation -= 90, a quarter turn per 90°
🖱️ The wheel sideways → or ←p.no++ or p.no--: a trackpad swipe or Shift + wheel turns one page per swipe

Gestures are on wherever controls are; controlslist=nogestures turns them off. While they are on, the page leaves vertical scrolling to the browser (touch-action: pan-y) and handles the other directions itself; with them off, two fingers zoom the browser again.

Your own touch-action on the page wins, and the gestures follow it: a move you leave to the browser is not a gesture. With pan-y pinch-zoom, two fingers zoom the browser while swipes still turn pages; with auto, the browser gets every touch. The sideways wheel has no CSS switch: nogestures turns it off.

css
pdf-page {
  touch-action: pan-y pinch-zoom; /* swipes turn pages, two fingers zoom */
}

Fullscreen

F or F11, the bar's ⛶ and PDFPageElement.toggleFullscreen() show the page alone on the screen, and Esc brings it back. CSS sees it as pdf-page:fullscreen, with what is behind it as ::backdrop, and --pdf-page-fullscreen-background-color colors the space around the page.

Note: iPhone has no fullscreen for elements: there, toggleFullscreen() resolves to false. iPad has it.

Turning pages quickly

While you read, a page with controls draws its neighbors in idle time, so the next page shows at once. break=prefetch turns that off.

Styling the controls

The bar, its buttons and its menu are parts (bar, bar-button, menu, menu-item and more), their colors are custom properties (--pdf-page-bar-*), and a page with controls matches :state(controls), with :state(bar) while its bar shows:

css
pdf-page {
  --pdf-page-bar-accent-color: oklch(55% 0.2 150);
}
pdf-page::part(bar) {
  border-radius: 0;
}

See also