Vue Components

inklayer-vue provides two top-level components: PdfViewer and PdfAnnotator. Built on Vue 3 Composition API, using Pinia for state management, integrating shadcn-vue UI components.

🚀 Try It Online

🎯 Live Demo

Explore the full capabilities of InkLayer, including PDF Viewer and PDF Annotator.

👉 Open Live Demo

💻 StackBlitz

Run and edit the Vue Starter directly in your browser—no local setup required.

👉 Open Vue Starter in StackBlitz

Installation

npm install inklayer-vue

Plugin Registration (Required)

You must register the InkLayer Vue plugin before using any components:

import { createApp } from 'vue'
import { inklayerVuePlugin } from 'inklayer-vue'
import App from './App.vue'

const app = createApp(App)
app.use(inklayerVuePlugin)
app.mount('#app')

Basic Import

// Components
import { PdfViewer, PdfAnnotator } from 'inklayer-vue'
import 'inklayer-vue/style'

// Types
import type {
  PdfViewerProps,
  PdfAnnotatorProps,
  User,
  Annotation,
  AnnotationPermissions,
} from 'inklayer-vue'

PdfViewer

Lightweight PDF viewer without annotation features.

Props

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

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

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>

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
annotationPermissionsAnnotationPermissions{ mode: 'unrestricted' }Collaboration permissions for create, edit, transform, status, delete, and reply actions
enableNativeAnnotationsbooleanfalseEnable PDF.js native annotations
enableRangeboolean | 'auto''auto'PDF range loading mode
defaultOptionsPartial<PdfAnnotatorOptions>Default annotation options
initialAnnotationsAnnotation[][]Initial annotation data
defaultShowAnnotationAuthorLabelsbooleanfalseWhether all annotation author labels are visible on initialization; users can still toggle them from the toolbar or with a shortcut
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

Collaboration Permissions

Vue and React share the same permission rules. Pass the application’s current user through user, then enable ownership control with annotationPermissions.

<script setup lang="ts">
import { PdfAnnotator } from 'inklayer-vue'
import type { AnnotationPermissions, User } from 'inklayer-vue'

const currentUser: User = { id: 'alice', name: 'Alice' }

const permissions: AnnotationPermissions = {
  mode: 'owner-only',
  can: ({ currentUser }) =>
    currentUser?.id === 'admin' ? true : undefined,
}
</script>

<template>
  <PdfAnnotator
    url="/document.pdf"
    :user="currentUser"
    :annotation-permissions="permissions"
    default-show-annotation-author-labels
    :layout-style="{ height: '100vh' }"
  />
</template>

For a fully read-only annotator, pass :annotation-permissions="{ can: () => false }". See Collaboration Permissions for the full action matrix, business-rule overrides, and security boundary.

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

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>

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'.