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

PropTypeDefaultDescription
urlstring | URLPDF file URL
datastring | number[] | ArrayBuffer | Uint8Array | Uint16Array | Uint32ArrayPDF binary data
themeSee theme color table below'violet'UI theme color
titlestring'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
layoutStyleCSSProperties{ width: '100vw', height: '100vh' }Container styles (Vue has default)
user{ id: string, name: string }{ id: 'null', name: 'unknown' }Current user info
enableNativeAnnotationsbooleanfalseEnable PDF.js native annotations
enableRangeboolean | 'auto''auto'PDF range loading mode
defaultOptionsPartial<PdfAnnotatorOptions>Default annotation options
initialAnnotationsAnnotation[][]Initial annotation data
defaultShowAnnotationsSidebarbooleanfalseWhether annotation sidebar is expanded by default

Theme Color Options

Color ValueDescription
grayGray
goldGold
bronzeBronze
brownBrown
yellowYellow
amberAmber
orangeOrange
tomatoTomato
redRed
rubyRuby
crimsonCrimson
pinkPink
plumPlum
purplePurple
violetViolet (default)
irisIris
indigoIndigo
blueBlue
cyanCyan
tealTeal
jadeJade
greenGreen
grassGrass
limeLime
mintMint
skySky

Events

React → Vue event mapping: React’s onXxx props correspond to Vue’s @xxx events (lowercase). For example: onSave@save, onLoad@load, onAnnotationAdded@annotation-added.

EventPayloadTrigger
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 NameSlot PropsDescription
actions{ onSave, getAnnotations, exportToExcel, exportToPdf }Custom actions area, rendered on the right side of toolbar

Slots (PdfViewer)

Slot NameSlot PropsDescription
actionscontext: PdfViewerContextValueCustom actions area
toolbarcontext: PdfViewerContextValueCompletely replace toolbar
sidebar-search-sidebarcontext: PdfViewerContextValueCustom search sidebar panel
sidebar-${key}context: PdfViewerContextValueDynamic slot, key comes from sidebar prop config

Exposed Methods

Call exposed methods via ref:

MethodDescription
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)

PropTypeDefaultDescription
showTextLayerbooleantrueShow text selection layer
showAnnotationsbooleanfalseShow existing annotations
defaultActiveSidebarKeystring | nullnullDefault expanded sidebar panel
toolbarComponent | ((context: PdfViewerContextValue) => VueNode)Custom toolbar
sidebarSidebarPanel[]Custom sidebar panels
actionsComponent | ((context: PdfViewerContextValue) => VueNode)Custom actions area
onDocumentLoaded(pdfViewer: PDFViewer | null) => voidPDF loading complete callback
onEventBusReady(eventBus: EventBus | null) => voidPDF.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.type values are 'Draw' | 'Enter' | 'Upload' (capitalized), NOT 'draw' | 'text' | 'image'.