# Vue File Preview [](https://www.npmjs.com/package/@eternalheart/vue-file-preview)[](https://github.com/wh131462/file-preview/blob/master/LICENSE)[](https://www.npmjs.com/package/@eternalheart/vue-file-preview)
English | [简体中文](./README.zh-CN.md)
A modern, feature-rich file preview component for Vue 3 with support for images, videos, audio, PDFs, Office documents (Word, Excel, PowerPoint), Markdown, and code files.
## Features
- **Modern UI** - Clean and modern interface with smooth animations
- **Multi-format Support** - Supports 20+ file formats
- **Two Display Modes** - Full-screen modal **or** inline embedded preview
- **Powerful Image Viewer** - Zoom, rotate, drag, mouse wheel zoom
- **Custom Video Player** - Built on Video.js, supports multiple video formats
- **Custom Audio Player** - Beautiful audio control interface
- **PDF Viewer** - Pagination support
- **Office Documents Support** - Word, Excel, PowerPoint file preview
- **Markdown Rendering** - GitHub Flavored Markdown support
- **Code Highlighting** - Supports 40+ programming languages
- **Responsive Design** - Adapts to all screen sizes
- **Keyboard Navigation** - Arrow keys and ESC support
## Installation
```bash
# Using npm
npm install @eternalheart/vue-file-preview
# Using yarn
yarn add @eternalheart/vue-file-preview
# Using pnpm
pnpm add @eternalheart/vue-file-preview
```
**Important:** You also need to import the CSS file:
```ts
import '@eternalheart/vue-file-preview/style.css';
```
### PDF.js Configuration (Optional)
If you need to preview PDF files, it's recommended to configure PDF.js to use local static files for better performance and stability:
#### Method 1: Use CDN (Default)
By default, the component automatically uses unpkg CDN to load PDF.js, no additional configuration needed.
#### Method 2: Use Local Static Files (Recommended for Production)
1. Copy PDF.js files to your public directory:
```bash
cp -r node_modules/pdfjs-dist/build/pdf.worker.min.mjs public/pdfjs/
cp -r node_modules/pdfjs-dist/cmaps public/pdfjs/
```
2. Configure PDF.js in your app entry:
```ts
import * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';
import { configurePdfWorker } from '@eternalheart/vue-file-preview';
configurePdfWorker(pdfjsLib, {
workerSrc: '/pdfjs/pdf.worker.min.mjs',
cMapUrl: '/pdfjs/cmaps/',
cMapPacked: true,
});
```
#### Auto-copy with Vite (Recommended)
Configure auto-copy in `vite.config.ts`:
```ts
import { defineConfig } from 'vite';
import { viteStaticCopy } from 'vite-plugin-static-copy';
export default defineConfig({
plugins: [
viteStaticCopy({
targets: [
{
src: 'node_modules/pdfjs-dist/build/pdf.worker.min.mjs',
dest: 'pdfjs'
},
{
src: 'node_modules/pdfjs-dist/cmaps',
dest: 'pdfjs'
}
]
})
]
});
```
### Vite Bundler Note (AVIF Decoder)
If your project bundler is Vite and you happen to have `@jsquash/avif` installed (transitively or directly), the production build may fail with:
```
[commonjs--resolver] Invalid value "iife" for option "worker.format"
- UMD and IIFE output formats are not supported for code-splitting builds.
file: .../@jsquash/avif/codec/enc/avif_enc_mt.js
```
This happens because `@jsquash/avif` ships a multi-threaded worker that uses code-splitting, while Vite's default `worker.format` is `'iife'`, which does not support split chunks.
**Fix** — add this to your `vite.config.ts`:
```ts
export default defineConfig({
// ... your existing config
worker: {
format: 'es',
},
});
```
`'es'` produces module workers (`type: 'module'`), supported by all modern browsers and compatible with code-splitting.
> Note: `@jsquash/avif` is only used as a fallback when the browser does not natively support AVIF (Chrome 85+, Firefox 93+, Safari 16+ all support it natively). If your target browsers cover the native list, you can also remove `@jsquash/avif` from your dependencies entirely.
## Quick Start
### Basic Usage
```vue
```
### Multiple Input Types
The component supports three types of file inputs:
```vue
```
### Embedded Mode (`FilePreviewEmbed`)
Besides the full-screen modal, the library also ships an **embedded** variant that renders the preview inline inside any container. Useful for detail panels, side-by-side layouts, dashboards, etc.
```vue
```
Differences from `FilePreviewModal`:
- No teleport, no full-screen overlay, no `isOpen` / `@close`
- Does **not** show the close button in the toolbar
- Keyboard navigation (←/→) is scoped to the embed container (focus-based)
- Size defaults to `width: 100%; height: 100%`; override via `width` / `height` props
```vue
```
## Supported File Formats
### Images
- **Formats**: JPG, PNG, GIF, WebP, SVG, BMP, ICO
- **Features**: Zoom (0.1x - 10x), rotate, drag, mouse wheel zoom, double-click reset
### Videos
- **Formats**: MP4, WebM, OGG, MOV, AVI, MKV, M4V, 3GP, FLV
- **Features**: Custom player, progress control, volume adjustment, fullscreen
### Audio
- **Formats**: MP3, WAV, OGG, M4A, AAC, FLAC
- **Features**: Custom player, progress bar, volume control, skip forward/backward
### Documents
- **PDF**: Pagination, zoom
- **Word**: DOCX format support
- **Excel**: XLSX format support
- **PowerPoint**: PPTX/PPT format support, slide preview
### Fonts
- **Formats**: TTF, OTF, WOFF, WOFF2
- **Features**: Font metadata (family, designer, version), character set preview, custom text input, multi-size display
### Code & Text
- **Markdown**: GitHub Flavored Markdown, code highlighting
- **Code Files**: JS, TS, Python, Java, C++, Go, Rust, and 40+ languages
- **Config/Logs**: YAML, TOML, INI, ENV, LOG, DIFF, PATCH, etc.
### Structured Data
- **JSON**: Auto formatting + syntax highlighting
- **CSV/TSV**: Zero-dependency parser, table view with headers and row/column stats
- **XML**: `DOMParser` validation + pretty print + syntax highlighting
### Subtitles & Lyrics
- **SRT / WebVTT**: Zero-dependency parser, structured cue list (index, time range, text)
- **LRC / Enhanced LRC**: Lyric files with `[mm:ss.xx]` line stamps (and inline `` per-word stamps for ELRC), with `[ti:][ar:][al:]` metadata header
- **ASS / SSA**: Advanced SubStation Alpha — extracts Dialogue events, strips `\N` `\h` and `{...}` override codes, surfaces Style names
- **TTML / DFXP**: W3C / Apple Music XML captions, supports `begin` / `end` / `dur` and ` `
### Archives
- **ZIP**: Tree view + inline preview for text/code/image entries, download fallback for other types
### Outlook Email
- **MSG**: Headers, body rendering, attachment list
### E-books
- **EPUB**: Chapter navigation, pagination
## Limitations & Performance
### Support Levels
**✅ Full Support (Production Ready)**
- Images (JPG, PNG, GIF, WebP, SVG, BMP, ICO)
- Videos (MP4, WebM, OGG)
- Audio (MP3, WAV, OGG)
- PDF
- Markdown
- Code files (40+ languages via Shiki, lazy-loaded)
- JSON, CSV, XML
**⚠️ Partial Support (Preview Only)**
- **Office (DOCX, XLSX, PPTX)**: Basic layout and text rendering. Complex formatting (charts, macros, embedded objects) may not render accurately.
- **ZIP**: Directory tree browsing + inline preview for text/code/images. Large archives (>100MB) may cause performance issues.
- **Fonts (TTF, OTF, WOFF)**: Metadata + character preview. Full font feature testing not supported.
**🧪 Experimental**
- **MSG (Outlook Email)**: Headers and plain text body. Complex HTML body may not render correctly.
- **EPUB**: Basic chapter navigation. CSS styling may differ from native readers. DRM-protected files not supported.
- **Subtitle formats (SRT, ASS, TTML, LRC)**: Text display only. No video sync or advanced styling.
### Performance Boundaries
| File Size | Status | Notes |
|-----------|--------|-------|
| < 50MB | ✅ Recommended | Smooth preview experience |
| 50-100MB | ⚠️ May lag | UI may become unresponsive during load |
| > 100MB | ❌ Not recommended | Browser memory limits may be exceeded |
**Special Cases:**
- **ZIP archives**: Performance depends on file count, not just size
- **Office documents**: Complex files (>200 pages, heavy images) may timeout
- **Code highlighting**: Files >5MB may take 3-5s to highlight
### Browser Compatibility
**Minimum Requirements:**
- Chrome 90+ / Edge 90+
- Firefox 88+
- Safari 14+
**Known Limitations:**
- **Safari iOS**: Video autoplay requires user interaction
- **Firefox**: AVIF support requires Firefox 93+ (fallback decoder included)
- **Office formats**: Rendering quality varies across browsers
- **EPUB**: Some CSS features unsupported in older browsers
## API Reference
### FilePreviewModal Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `files` | `PreviewFileInput[]` | ✅ | Array of files (supports File objects, file objects, or URL strings) |
| `currentIndex` | `number` | ✅ | Current file index |
| `isOpen` | `boolean` | ✅ | Whether the modal is open |
| `customRenderers` | `CustomRenderer[]` | ❌ | Custom renderers for specific file types |
| `locale` | `Locale` | ❌ | UI language (`'zh-CN'` default, `'en-US'` built-in) |
| `messages` | `Partial>>` | ❌ | Custom translation overrides |
| `headless` | `boolean` | ❌ | Headless mode — hides toolbar and navigation arrows |
| `theme` | `Theme` | ❌ | Theme mode: `'auto' \| 'dark' \| 'light'` (default `'dark'`) |
| `showDownload` | `boolean` | ❌ | Whether to show the download button (default `true`) |
### FilePreviewModal Events
| Event | Payload | Description |
|-------|---------|-------------|
| `close` | - | Emitted when the modal should close |
| `navigate` | `number` | Emitted when navigating to a different file index |
### FilePreviewEmbed Props
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `files` | `PreviewFileInput[]` | ✅ | - | Array of files |
| `currentIndex` | `number` | ❌ | `0` | Current file index |
| `customRenderers` | `CustomRenderer[]` | ❌ | - | Custom renderers |
| `width` | `number \| string` | ❌ | `'100%'` | Container width |
| `height` | `number \| string` | ❌ | `'100%'` | Container height |
| `locale` | `Locale` | ❌ | `'zh-CN'` | UI language (`'zh-CN'` or `'en-US'`) |
| `messages` | `Partial>>` | ❌ | - | Custom translation overrides |
| `headless` | `boolean` | ❌ | `false` | Headless mode — hides toolbar and navigation arrows |
| `theme` | `Theme` | ❌ | `'dark'` | Theme mode: `'auto' \| 'dark' \| 'light'` |
| `showDownload` | `boolean` | ❌ | `true` | Whether to show the download button |
### FilePreviewEmbed Events
| Event | Payload | Description |
|-------|---------|-------------|
| `navigate` | `number` | Emitted when navigating to a different file index |
### FilePreviewContent (advanced)
Both `FilePreviewModal` and `FilePreviewEmbed` are thin wrappers around the exported lower-level `FilePreviewContent` component. Use it directly when building a fully custom wrapper:
```vue
```
### File Type Definitions
```typescript
// Supports three types of file input
type PreviewFileInput = File | PreviewFileLink | string;
// 1. Native File object (Browser File API)
const file: File = ...;
// 2. File object
interface PreviewFileLink {
id?: string; // Optional unique identifier
name: string; // File name
type: string; // MIME type
url: string; // File URL (supports blob URLs and HTTP URLs)
size?: number; // File size in bytes
}
// 3. HTTP URL string
const url: string = 'https://example.com/file.pdf';
```
## Custom Renderers
The library supports custom renderers for handling file types not built-in. Custom renderers can optionally provide toolbar configurations and integrate with the library's architecture.
### Event-Driven Toolbar Updates
Custom renderers can implement real-time toolbar updates using Vue 3's reactivity system:
**Benefits:**
- **Real-time updates**: Toolbar reflects state changes immediately via Vue reactivity
- **Better performance**: No polling overhead, leverages Vue's efficient change detection
- **Type-safe**: Full TypeScript support with proper interfaces
**Implementation:**
```vue
Your custom renderer UI
```
**Main component usage:**
```vue
```
The main component automatically tracks reactive changes in `getToolbarGroups()` via Vue's reactivity system. No manual subscription needed.
### Renderer Lazy Loading
All built-in renderers use code-splitting via `defineAsyncComponent` to minimize the main bundle size and improve initial load performance.
**Architecture:**
- **Registration**: Renderers register in `src/renderers/lazy.ts` using `defineAsyncComponent` wrappers
- **Loading**: Each renderer is a separate chunk, loaded on-demand when needed
- **Fallback**: `RendererLoading` component handles the loading state
**Bundle Size Impact:**
- Main entry point: gzip ≤ 60 KB (strictly enforced by CI)
- Each renderer: separate async chunk
- Total library: gzip ≤ 500 KB (all renderers combined)
**Implementation Example:**
```ts
// src/renderers/lazy.ts
import { defineAsyncComponent } from 'vue';
const wrap = (loader: () => Promise) =>
defineAsyncComponent({
loader,
loadingComponent: RendererLoading,
delay: 0
});
export const CustomRenderer = wrap(() => import('./Custom/index.vue'));
```
```vue
```
**For Custom Renderers:**
If you want your custom renderer to benefit from code-splitting, use the same pattern:
```vue
```
### i18n Integration
Custom renderers can access the library's i18n system via the `useTranslator()` composable for consistent multilingual support.
**Architecture:**
- **Dictionary Source**: `file-preview-core/src/i18n/messages/` (zh-CN.ts, en-US.ts)
- **No Hardcoding**: All user-visible text must use translation keys
- **Automatic Locale Switching**: Follows the `locale` prop passed to `FilePreviewModal`
**Usage in Custom Renderers:**
```vue