Skip to main content

Document & viewing

Viewer

Layout, rendering, zoom, navigation, links and focus effects.


Viewer.Root creates the ViewerState: zoom and fit modes, scroll mode and columns, rotation, page theme, navigation and the text selection. Viewer.Viewport scrolls, Viewer.Pages lays the pages out and each Viewer.Page hosts its layers.

Anatomy

<Viewer.Root>
	<Viewer.Viewport>
		<Viewer.Pages>
			{#snippet children({ pageNumber })}
				<Viewer.Page {pageNumber}>
					<Viewer.Canvas />    <!-- the page bitmap -->
					<Viewer.TextLayer /> <!-- selectable text -->
					<Viewer.LinkLayer /> <!-- the PDF's own links -->
					<Viewer.Focus />     <!-- focus effects -->
				</Viewer.Page>
			{/snippet}
		</Viewer.Pages>
	</Viewer.Viewport>
	<Viewer.LinkPreview /> <!-- hover preview of link targets -->
	<Viewer.BackButton />  <!-- after a jump -->
</Viewer.Root>
<Viewer.Root>
	<Viewer.Viewport>
		<Viewer.Pages>
			{#snippet children({ pageNumber })}
				<Viewer.Page {pageNumber}>
					<Viewer.Canvas />    <!-- the page bitmap -->
					<Viewer.TextLayer /> <!-- selectable text -->
					<Viewer.LinkLayer /> <!-- the PDF's own links -->
					<Viewer.Focus />     <!-- focus effects -->
				</Viewer.Page>
			{/snippet}
		</Viewer.Pages>
	</Viewer.Viewport>
	<Viewer.LinkPreview /> <!-- hover preview of link targets -->
	<Viewer.BackButton />  <!-- after a jump -->
</Viewer.Root>

Usage

<Viewer.Root bind:viewer bind:page zoomMode="page-width" columns="auto" pageTheme={pageThemes.paper({ dark })}>
	…
</Viewer.Root>

<button onclick={() => viewer.navigate({ dest: 'section.3' })}>Section 3</button>
<Viewer.Root bind:viewer bind:page zoomMode="page-width" columns="auto" pageTheme={pageThemes.paper({ dark })}>
	…
</Viewer.Root>

<button onclick={() => viewer.navigate({ dest: 'section.3' })}>Section 3</button>

Guides: Viewer & layout, Navigation & focus, Page themes.

API reference

Viewer.Root

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
zoom bindable 1 = 100%. Bindable. number 1
onZoomChange (zoom: number) => void —
zoomMode bindable 'auto' | 'page-width' | 'page-height' | 'page-fit' | 'manual'. Bindable. ZoomMode 'auto'
onZoomModeChange (mode: ZoomMode) => void —
page bindable Current page (1-based). Bindable; setting it scrolls. number 1
onPageChange (page: number) => void —
rotation bindable Rotation 0
onRotationChange (rotation: Rotation) => void —
scrollMode bindable ScrollMode 'vertical'
onScrollModeChange (mode: ScrollMode) => void —
columns bindable Pages per row: 1–4 or 'auto' (more pages per row as you zoom out). Bindable. Columns 1
onColumnsChange (columns: Columns) => void —
maxColumns Upper bound for 'auto' columns. Default 4. number —
firstPageAlone Book layout: first page alone (cover), then spreads. boolean —
smoothZoom Ease zoom changes (wheel, buttons, fit modes, zoomTo). Default true. boolean —
transformZoom Zoom gestures show as a transform, laid out and drawn once at the end (smoother on long documents; fixed-size parts scale along until it lands). Default false. boolean —
oversampling Render zoomed-out pages at up to 2× so quick zoom-ins stay sharp. Default true. boolean —
detailMinWidth Pages narrower than this (CSS px) skip text layers / text indexing. Default 260. number —
focusDuration Focus highlight duration in ms. Default 1800. number —
focusHighlight Effect when a link lands on a figure, table, section…: 'pulse' (default), 'outline', 'spotlight' or a custom name for `Viewer.Focus`'s `child`. FocusHighlight —
focusPadding Padding (PDF points) around focused rects. Default 6. number | [number, number] —
messages UI strings (e.g. a translation); merged over setMessages() and the English defaults. Partial<Messages> —
keymap Keyboard shortcuts (merged over `defaultKeymap`); annotations use them too. Partial<Keymap> —
pageTheme Page content theme: 'none' | 'invert' | 'dim' | 'sepia' | 'recolor' or a strategy. PageThemeInput —
theme UI theme hint exposed as data-theme. 'light' | 'dark' | 'system' 'system'
pageFrame Page edge style (exposed as data-page-frame, styled by styles.css): 'shadow' (default), 'border', 'rounded', 'flat' (no edge) or 'none' (no frame, no background). 'shadow' | 'border' | 'rounded' | 'flat' | 'none' | (string & {}) 'shadow'
overscan Render pages within N viewport-lengths. Default 1. number —
maxCanvasPixels number —
wheelZoom boolean —
keyboard Shortcuts on the viewport (default), anywhere but text fields and dialogs ('document'), or off. boolean | 'document' —
zoomSteps number[] —
minZoom Smallest and largest zoom any way of zooming reaches (pinch, wheel, steps, fit modes). Defaults 0.1 and 10. number —
maxZoom number —
zoomLocked Lock the zoom (user zooming does nothing; a fit mode keeps fitting). boolean —
viewer bindable The viewer state (bind:viewer to call commands from outside). ViewerState —
Snippet prop Type
viewer ViewerState
Data attributes data-columnsdata-page-framedata-page-themedata-pdf-viewerdata-statusdata-theme

Viewer.Viewport

Renders a <div> (or your element via child) and accepts its HTML attributes.

No props of its own besides ref, child and children.

Snippet prop Type
viewer ViewerState

Viewer.Pages

Renders a <div> (or your element via child) and accepts its HTML attributes.

No props of its own besides ref, child and children.

Snippet prop Type
pageNumber number

Viewer.Page

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
pageNumber required number —
Snippet prop Type
pageNumber number
width number
height number
isNear boolean
isVisible boolean
isCurrent boolean
scale number

Viewer.Canvas

Renders a <div> (or your element via child) and accepts its HTML attributes.

No props of its own besides ref, child and children.

Snippet prop Type
rendered boolean

Viewer.TextLayer

Renders a <div> (or your element via child) and accepts its HTML attributes.

No props of its own besides ref, child and children.

Viewer.Focus

Renders a <div> (or your element via child) and accepts its HTML attributes.

No props of its own besides ref, child and children.

Snippet prop Type
highlight FocusHighlight
duration number
Data attributes data-highlightdata-pdf-focusdata-pdf-focus-clip

Viewer.LinkLayer

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
external How external URLs open. Default 'new-tab'. 'new-tab' | 'same-tab' 'new-tab'
onLinkClick Replace the click action (e.g. open a cited paper in your app). Return false to skip the default. (link: LinkInfo, event: MouseEvent) => void | false —
Snippet prop Type
links The link hotspots: render them inside your own element (`child`). Snippet
Data attributes data-kinddata-pdf-linkdata-pdf-link-layer

Viewer.LinkPreview

Renders a <div> (or your element via child) and accepts its HTML attributes.

Prop Type Default
width Preview width in CSS px. Default 420. number 420
kinds Only preview these link kinds. LinkKind[] —
forceMount Keep rendering `child` while closed (with `open: false`) for exit transitions. boolean false
onOpenChange (open: boolean) => void —
placement 'top' | 'bottom' | 'left' | 'right' 'top'
Snippet prop Type
open boolean
kind LinkKind
page number
url string
canvasProps Record<string | symbol, unknown>
Data attributes data-force-mountdata-kinddata-loadingdata-partdata-pdf-link-previewdata-pdf-link-preview-canvasdata-state

Viewer.BackButton

Renders a <button> (or your element via child) and accepts its HTML attributes.

Prop Type Default
forceMount boolean false
Snippet prop Type
page number | null
label string
Data attributes data-pdf-back-buttondata-state