Vue Components
inklayer-vue provides two top-level components: PdfAnnotator and PdfViewer. Built on Vue 3 Composition API, using Pinia for state management, integrating shadcn-vue UI components.
Installation
npm install inklayer-vue
Basic Import
// Components
import { PdfAnnotator, PdfViewer } from 'inklayer-vue'
import 'inklayer-vue/style'
// Types
import type { PdfAnnotatorProps, PdfViewerProps, User, Annotation } from 'inklayer-vue'
PdfAnnotator
Full-featured PDF annotation component with built-in toolbar, annotation editing, and sidebar.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| url | string | URL | — | PDF file URL |
| data | string | number[] | ArrayBuffer | Uint8Array | Uint16Array | Uint32Array | — | PDF binary data |
| theme | See theme color table below | 'violet' | UI theme color |
| title | string | 'PDF ANNOTATOR' | Annotator title |
| locale | 'zh-CN' | 'en-US' | 'zh-CN' | UI language |
| initialScale | 'auto' | 'page-actual' | 'page-fit' | 'page-width' | number | 'auto' | Initial zoom scale |
| layoutStyle | CSSProperties | { width: '100vw', height: '100vh' } | Container styles (Vue has default) |
| user | { id: string, name: string } | { id: 'null', name: 'unknown' } | Current user info |
| enableNativeAnnotations | boolean | false | Enable PDF.js native annotations |
| enableRange | boolean | 'auto' | 'auto' | PDF range loading mode |
| defaultOptions | Partial<PdfAnnotatorOptions> | — | Default annotation options |
| initialAnnotations | Annotation[] | [] | Initial annotation data |
| defaultShowAnnotationsSidebar | boolean | false | Whether annotation sidebar is expanded by default |
Theme Color Options
| Color Value | Description |
|---|---|
gray | Gray |
gold | Gold |
bronze | Bronze |
brown | Brown |
yellow | Yellow |
amber | Amber |
orange | Orange |
tomato | Tomato |
red | Red |
ruby | Ruby |
crimson | Crimson |
pink | Pink |
plum | Plum |
purple | Purple |
violet | Violet (default) |
iris | Iris |
indigo | Indigo |
blue | Blue |
cyan | Cyan |
teal | Teal |
jade | Jade |
green | Green |
grass | Grass |
lime | Lime |
mint | Mint |
sky | Sky |
Events
React → Vue event mapping: React’s
onXxxprops correspond to Vue’s@xxxevents (lowercase). For example:onSave→@save,onLoad→@load,onAnnotationAdded→@annotation-added.
| Event | Payload | Trigger |
|---|---|---|
| save | (annotations: Annotation[]) | User clicks save |
| load | () | PDF loading complete |
| annotation-added | (annotation: Annotation) | New annotation created |
| annotation-deleted | (id: string) | Annotation deleted |
| annotation-selected | (annotation: Annotation | null, isClick: boolean) | Annotation selected/deselected |
| annotation-updated | (annotation: Annotation) | Annotation updated |
Slots (PdfAnnotator)
| Slot Name | Slot Props | Description |
|---|---|---|
actions | { onSave, getAnnotations, exportToExcel, exportToPdf } | Custom actions area, rendered on the right side of toolbar |
Slots (PdfViewer)
| Slot Name | Slot Props | Description |
|---|---|---|
actions | context: PdfViewerContextValue | Custom actions area |
toolbar | context: PdfViewerContextValue | Completely replace toolbar |
sidebar-search-sidebar | context: PdfViewerContextValue | Custom search sidebar panel |
sidebar-${key} | context: PdfViewerContextValue | Dynamic slot, key comes from sidebar prop config |
Exposed Methods
Call exposed methods via ref:
| Method | Description |
|---|---|
save() | Trigger save operation |
getAnnotations() | Get all current annotation data |
Full Example: Annotator with Persistence and Slots
<script setup lang="ts">
import { ref } from 'vue'
import { PdfAnnotator } from 'inklayer-vue'
import 'inklayer-vue/style'
import type { Annotation } from 'inklayer-vue'
const annotatorRef = ref<InstanceType<typeof PdfAnnotator>>()
const annotations = ref<Annotation[]>([])
function handleSave(data: Annotation[]) {
annotations.value = data
// Send to backend
fetch('/api/annotations', {
method: 'POST',
body: JSON.stringify(data),
})
}
</script>
<template>
<PdfAnnotator
ref="annotatorRef"
url="/document.pdf"
locale="en-US"
:layout-style="{ height: '96vh' }"
:enable-range="true"
:default-show-annotations-sidebar="true"
:user="{ id: '9527', name: 'Lao Mai' }"
:enable-native-annotations="true"
:initial-annotations="[]"
:default-options="defaultOptions"
@save="handleSave"
@load="() => console.log('PDF Loaded')"
@annotation-added="(a) => console.log('Added:', a.id)"
@annotation-deleted="(id) => console.log('Deleted:', id)"
@annotation-updated="(a) => console.log('Updated:', a.id)"
@annotation-selected="(a, isClick) => console.log('Selected:', a?.id, isClick)"
>
<template #actions="{ onSave, getAnnotations, exportToExcel, exportToPdf }">
<button @click="onSave()">Save</button>
<button @click="console.log(getAnnotations())">Get Annotations</button>
<button @click="exportToExcel('my-export')">Export Excel</button>
<button @click="exportToPdf('my-export')">Export PDF</button>
</template>
</PdfAnnotator>
</template>
PdfViewer
Lightweight PDF viewer without annotation features.
Props (inherits PdfAnnotator base props, plus the following)
| Prop | Type | Default | Description |
|---|---|---|---|
| showTextLayer | boolean | true | Show text selection layer |
| showAnnotations | boolean | false | Show existing annotations |
| defaultActiveSidebarKey | string | null | null | Default expanded sidebar panel |
| toolbar | Component | ((context: PdfViewerContextValue) => VueNode) | — | Custom toolbar |
| sidebar | SidebarPanel[] | — | Custom sidebar panels |
| actions | Component | ((context: PdfViewerContextValue) => VueNode) | — | Custom actions area |
| onDocumentLoaded | (pdfViewer: PDFViewer | null) => void | — | PDF loading complete callback |
| onEventBusReady | (eventBus: EventBus | null) => void | — | PDF.js EventBus ready callback |
Viewer Full Example
<script setup lang="ts">
import { ref } from 'vue'
import { PdfViewer } from 'inklayer-vue'
import 'inklayer-vue/style'
function onEventBusReady(eventBus: any) {
eventBus?.on('page-rendered', (e: any) => console.log('Page:', e.pageNumber))
}
function onDocumentLoaded(pdfViewer: any) {
console.log('Document loaded:', pdfViewer)
}
</script>
<template>
<PdfViewer
:enable-range="false"
title="PDF VIEWER CUSTOM"
:url="pdfUrl"
:layout-style="{ width: '100vw', height: '96vh' }"
:show-text-layer="false"
:show-annotations="true"
:default-active-sidebar-key="null"
:sidebar="customSidebar"
@event-bus-ready="onEventBusReady"
@document-loaded="onDocumentLoaded"
>
<template #actions="{ context }">
<button @click="context.print()">Print</button>
<button @click="context.download('test')">Download</button>
</template>
<template #toolbar="{ context }">
<button @click="context.toggleSidebar()">Toggle</button>
</template>
<template #sidebar-sidebar-1="{ context }">
<div>Custom Panel 1</div>
</template>
</PdfViewer>
</template>
SidebarPanel Type
The sidebar prop accepts SidebarPanel[], defining custom sidebar panels:
interface SidebarPanel {
key: string // Panel unique key
title: string // Panel title
icon: Vue.VNode // Panel icon
render: (context: PdfViewerContextValue) => Vue.VNode // Panel content render function
}
PdfViewerContextValue Type
The function form of actions, toolbar, sidebar receives a PdfViewerContextValue object:
interface PdfViewerContextValue {
pdfViewer: PDFViewer | null // PDFViewer instance
currentPage: number // Current page number (0-based)
totalPages: number // Total pages
scale: number // Current zoom scale
print: () => void // Print
download: (filename?: string) => void // Download
toggleSidebar: () => void // Toggle sidebar
scrollPageIntoView: (opts: { pageNumber: number }) => void // Scroll to page
}
PdfAnnotatorOptions Configuration
Customize default annotation behavior via the defaultOptions prop:
interface PdfAnnotatorOptions {
colors?: string[] // Available color list
signature?: {
colors?: string[] // Signature color options
type?: 'Draw' | 'Enter' | 'Upload' // Signature type (note capital first letter)
maxSize?: number // Max signature image file size (bytes)
accept?: string // Accepted image formats
defaultSignature?: string[] // Default signature list
defaultFont?: { // Default font list
label: string
value: string
external?: boolean
url?: string // External font URL
}[]
}
stamp?: {
maxSize?: number // Stamp image max file size
accept?: string // Accepted image formats
defaultStamp?: string[] // Default stamp list
editor?: { // Stamp editor config
defaultBackgroundColor?: string
defaultBorderColor?: string
defaultBorderStyle?: 'none' | 'solid' | 'dashed'
defaultTextColor?: string
defaultFont?: {
label: string
value: string
}[]
}
}
}
Note:
signature.typevalues are'Draw' | 'Enter' | 'Upload'(capitalized), NOT'draw' | 'text' | 'image'.