v-file-preview
v0.1.3
Published
Production ready file viewer for Vue 3
Readme
Preview PDFs, Word documents, Excel spreadsheets, images, videos, audio, and code/text files — all from a single component. Just pass a URL or a File/Blob object and v-file-preview picks the right viewer automatically.
✨ Features
- 📄 PDF — Rendered with
pdfjs-dist. Built-in toolbar with pagination, zoom, fullscreen, and download. - 📝 DOCX — Rendered via
@vue-office/docx. - 📊 Excel / CSV — Rendered via
@vue-office/excel(.xlsx,.xls,.csv). - 🖼️ Images — Native
<img>tag (.jpg,.jpeg,.png,.webp,.gif,.svg). - 🎬 Video — Native
<video>tag (.mp4,.webm,.ogg,.mov). - 🎵 Audio — Native
<audio>tag (.mp3,.wav). - 💻 Code / Text — Syntax-highlighted with CodeMirror (
.json,.js,.ts,.vue,.html,.css,.txt,.md). - 🔒 Download protection — Optionally disable right-click save and the browser download button.
- ⚡ KeepAlive caching — Switching between files doesn't re-render previously loaded previews.
- 🧩 Vue 3 plugin — Register globally or import the component locally.
- 📦 TypeScript — Full type definitions included out of the box.
📦 Installation
npm
npm install v-file-previewyarn
yarn add v-file-previewpnpm
pnpm add v-file-previewDon't forget to follow me on GitHub!
🚀 Quick Start
Global Registration (Plugin)
// main.ts
import { createApp } from 'vue'
import VFileViewerPlugin from 'v-file-preview'
import App from './App.vue'
const app = createApp(App)
app.use(VFileViewerPlugin) // registers <VFileViewer> globally
app.mount('#app')Local Import (Recommended)
<script setup lang="ts">
import { VFileViewer } from 'v-file-preview'
</script>
<template>
<VFileViewer
url="https://example.com/sample.pdf"
name="report.pdf" />
</template>📖 Usage Examples
Preview a File from URL
<template>
<VFileViewer
url="https://example.com/document.pdf"
name="document.pdf"
width="100%"
height="600px" />
</template>Preview a File / Blob Object
<script setup lang="ts">
import { ref } from 'vue'
import { VFileViewer } from 'v-file-preview'
const selectedFile = ref<File | null>(null)
const onFileChange = (e: Event) => {
const input = e.target as HTMLInputElement
selectedFile.value = input.files?.[0] ?? null
}
</script>
<template>
<input
type="file"
@change="onFileChange" />
<VFileViewer
v-if="selectedFile"
:file="selectedFile"
:name="selectedFile.name" />
</template>Disable Download
<template>
<VFileViewer
url="/confidential-report.pdf"
name="report.pdf"
:can-download="false" />
</template>Handle Events
<script setup lang="ts">
import { VFileViewer, useViewer } from 'v-file-preview'
const {
isLoading,
isError,
errorMessage,
handleLoadStart,
handleLoadSuccess,
handleLoadError,
} = useViewer()
</script>
<template>
<p v-if="isLoading">Loading preview…</p>
<p
v-if="isError"
style="color: red;">
{{ errorMessage }}
</p>
<VFileViewer
url="/presentation.docx"
name="presentation.docx"
@rendered="handleLoadSuccess"
@error="handleLoadError" />
</template>⚙️ Props
| Prop | Type | Default | Description |
| ------------- | ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| file | File \| Blob \| null | undefined | A File or Blob object to preview. Takes priority over url. |
| url | string \| null | undefined | A URL pointing to the file to preview. |
| name | string \| null | undefined | An explicit file name (with extension) used to determine the file type when it can't be inferred from the file or url. |
| width | string | '100%' | CSS width of the viewer wrapper. |
| height | string | '100%' | CSS height of the viewer wrapper. |
| canDownload | boolean | true | When false, disables right-click saving (images/PDFs), hides the download button (PDFs), and removes the browser download control (video/audio). |
How is the file type detected?
The extension is extracted from (in order of priority):
file.name(iffileis aFilewith a name)- The
nameprop- The pathname of the
urlThe extracted extension is then matched against the built-in extension map.
📡 Events
| Event | Payload | Description |
| ---------- | ------- | ----------------------------------------------------------------------------------------------------- |
| rendered | — | Emitted when the file has been successfully loaded and rendered. |
| error | Error | Emitted when loading or rendering fails. The payload is an Error object with a descriptive message. |
🪝 useViewer Composable
A convenience composable that provides reactive loading/error state for pairing with VFileViewer events.
import { useViewer } from 'v-file-preview'
const {
isLoading, // Ref<boolean>
isError, // Ref<boolean>
errorMessage, // Ref<string>
handleLoadStart, // () => void — call when switching files
handleLoadSuccess, // () => void — bind to @rendered
handleLoadError, // (err: Error) => void — bind to @error
} = useViewer()🗂️ Supported File Types
| Category | Extensions | Viewer Engine |
| --------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------- |
| PDF | .pdf | pdfjs-dist — custom canvas renderer with pagination, zoom, fullscreen |
| Word | .docx | @vue-office/docx |
| Spreadsheet | .xlsx, .xls, .csv | @vue-office/excel |
| Image | .jpg, .jpeg, .png, .webp, .gif, .svg | Native <img> |
| Video | .mp4, .webm, .ogg, .mov | Native <video> |
| Audio | .mp3, .wav | Native <audio> |
| Code / Text | .json, .js, .ts, .vue, .html, .css, .txt, .md | CodeMirror 6 (read-only) |
| Unknown | everything else | Friendly "unsupported" placeholder |
🎨 CSS Customization
The wrapper element uses the class v-file-preview-wrapper. You can override its styles to match your design system:
/* Override the wrapper border, radius, and background */
.v-file-preview-wrapper {
border-radius: 12px;
border: 1px solid #d1d5db;
background-color: #fafafa;
}Internal CSS Classes Reference
Each sub-viewer exposes scoped CSS classes. Because they are scoped, target them through the wrapper using :deep() if you need fine-grained control.
| Viewer | Key Classes | Description |
| --------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| PDF | .pdf-viewer-container, .pdf-toolbar, .toolbar-btn, .pdf-canvas-wrapper, .pdf-canvas | PDF viewer layout, toolbar buttons, and canvas |
| Office | .office-viewer-container | DOCX / Excel container |
| Image | .image-viewer-container, .image-content | Image wrapper and the <img> element |
| Media | .media-viewer-container, .media-video, .media-audio | Video & audio wrapper and elements |
| Code | .code-viewer-container, .cm-wrapper | Code viewer and CodeMirror wrapper |
| Unsupported | .unsupported-container, .icon-wrapper, .title, .subtitle | Unsupported file fallback UI |
Example — customizing the PDF toolbar:
<style>
.v-file-preview-wrapper :deep(.pdf-toolbar) {
background-color: #1f2937;
color: #f9fafb;
}
.v-file-preview-wrapper :deep(.toolbar-btn) {
color: #d1d5db;
}
.v-file-preview-wrapper :deep(.toolbar-btn:hover:not(:disabled)) {
background-color: #374151;
color: #ffffff;
}
</style>Example — dark theme for the image viewer:
<style>
.v-file-preview-wrapper :deep(.image-viewer-container) {
background-color: #111827;
}
</style>🏗️ TypeScript
All public types are exported and available for direct import:
import type { VFileViewerProps } from 'v-file-preview'
import { FileCategory } from 'v-file-preview'
// FileCategory enum values
FileCategory.PDF // 'pdf'
FileCategory.DOCX // 'docx'
FileCategory.EXCEL // 'excel'
FileCategory.IMAGE // 'image'
FileCategory.VIDEO // 'video'
FileCategory.AUDIO // 'audio'
FileCategory.CODE // 'code'
FileCategory.UNKNOWN // 'unknown'