A secure PDF viewer component for Vue 3. Uses canvas-only rendering to prevent XSS attacks from malicious PDF files.
- Canvas-only rendering -- PDF pages are rasterized to
<canvas>, notextLayerorannotationLayerDOM elements are created, eliminating all XSS injection vectors - JavaScript execution disabled --
isEvalSupported: falseprevents PDF.js from executing embedded JavaScript - External resource blocking --
disableAutoFetch: trueblocks external resource loading (SSRF prevention) - Font injection prevention --
disableFontFace: trueblocks@font-faceinjection - Built-in toolbar with page navigation and zoom controls
- Keyboard shortcuts support
- Three input modes: URL, File object, and ArrayBuffer
- TypeScript support
npm install secure-pdf-viewer-vue3 pdfjs-dist<template>
<SecurePdfViewer src="https://example.com/document.pdf" />
</template>
<script setup>
import { SecurePdfViewer } from 'secure-pdf-viewer-vue3';
</script><template>
<div>
<input type="file" accept=".pdf" @change="onFileChange" />
<SecurePdfViewer v-if="pdfFile" :file="pdfFile" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import { SecurePdfViewer } from 'secure-pdf-viewer-vue3';
const pdfFile = ref(null);
function onFileChange(e) {
pdfFile.value = e.target.files[0];
}
</script><template>
<SecurePdfViewer v-if="pdfData" :data="pdfData" />
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { SecurePdfViewer } from 'secure-pdf-viewer-vue3';
const pdfData = ref(null);
onMounted(async () => {
const response = await fetch('/document.pdf');
pdfData.value = await response.arrayBuffer();
});
</script><template>
<SecurePdfViewer
ref="viewerRef"
src="/docs/report.pdf"
:initial-scale="1.5"
:show-toolbar="true"
worker-src="/pdf.worker.min.mjs"
@page-change="onPageChange"
@scale-change="onScaleChange"
@load-state-change="onLoadStateChange"
@error="onError"
/>
</template>
<script setup>
import { ref } from 'vue';
import { SecurePdfViewer } from 'secure-pdf-viewer-vue3';
const viewerRef = ref(null);
function onPageChange(page, totalPages) {
console.log(`Page ${page} of ${totalPages}`);
}
function onScaleChange(scale) {
console.log(`Zoom: ${Math.round(scale * 100)}%`);
}
function onLoadStateChange(state) {
console.log(`Load state: ${state}`);
}
function onError(error) {
console.error('PDF error:', error);
}
// Access exposed methods via ref
function jumpToPage5() {
viewerRef.value?.goToPage(5);
}
</script>| Prop | Type | Default | Description |
|---|---|---|---|
src |
string |
undefined |
URL of the PDF file |
file |
File |
undefined |
File object (for file upload scenarios) |
data |
ArrayBuffer | Uint8Array |
undefined |
Raw PDF data |
initialScale |
number |
1.0 |
Initial zoom scale |
minScale |
number |
0.25 |
Minimum zoom scale |
maxScale |
number |
5.0 |
Maximum zoom scale |
showToolbar |
boolean |
true |
Whether to show the toolbar |
class |
string |
'' |
Custom CSS class for the container |
style |
object |
{} |
Custom inline styles for the container |
workerSrc |
string |
undefined |
Custom path to the PDF.js worker file |
pixelRatio |
number |
window.devicePixelRatio |
Device pixel ratio for rendering |
disableDownload |
boolean |
false |
Disable the download button in toolbar |
| Event | Payload | Description |
|---|---|---|
load-state-change |
state: 'idle' | 'loading' | 'ready' | 'error' |
Fired when the loading state changes |
page-change |
page: number, totalPages: number |
Fired when the current page changes |
scale-change |
scale: number |
Fired when the zoom scale changes |
error |
error: Error |
Fired when an error occurs |
Access these methods via a template ref:
| Method | Signature | Description |
|---|---|---|
goToPage |
(page: number) => void |
Navigate to a specific page |
setScale |
(scale: number) => void |
Set the zoom scale (clamped to min/max) |
getState |
() => { currentPage, totalPages, scale } |
Get the current viewer state |
When the viewer is focused:
| Key | Action |
|---|---|
Arrow Left / Arrow Up |
Previous page |
Arrow Right / Arrow Down |
Next page |
Ctrl + |
Zoom in |
Ctrl - |
Zoom out |
This component is designed with security as the core principle:
-
No DOM injection -- PDF content is rendered purely to a
<canvas>element. NoinnerHTML,textLayer, orannotationLayeris used, which eliminates all XSS attack vectors from malicious PDFs. -
JavaScript execution disabled -- The
isEvalSupported: falseconfiguration prevents PDF.js from executing any JavaScript embedded in PDF files. -
External resource blocking --
disableAutoFetch: trueprevents the PDF from loading external resources, mitigating SSRF attacks. -
Font injection prevention --
disableFontFace: trueblocks@font-faceCSS injection from PDF fonts.
For production deployments with strict CSP (Content Security Policy), place the pdf.worker.min.mjs file in your public directory and provide its path via the workerSrc prop:
<SecurePdfViewer
src="/document.pdf"
worker-src="/pdf.worker.min.mjs"
/>