Complete PDF Editing Solution for Your Web Applications
The PDF Editor SDK is a powerful, framework-agnostic solution that allows you to integrate a complete PDF editing experience into your web applications. Built on top of Fabric.js and Vue 3, it provides a rich set of features for manipulating PDF documents directly in the browser.
Add, edit, and style text with full typography control
Insert, resize, and manipulate images
Create lines, rectangles, circles, and custom shapes
Generate QR codes and barcodes on the fly
Add signature images to documents
Protect documents with custom watermarks
Export to PDF, PNG, or JPEG formats
Work with multiple pages seamlessly
Copy the built library files to your project:
// Copy these files from dist/lib/ to your project
pdf-editor-sdk.es.js
pdf-editor-sdk.umd.js
pdf-editor-sdk.css
pdf-editor-sdk.d.ts
npm install @your-company/pdf-editor-sdk
# or
yarn add @your-company/pdf-editor-sdk
npm install git+https://github.com/your-company/pdf-editor-sdk.git
# or add to package.json
{
"dependencies": {
"pdf-editor-sdk": "git+https://github.com/your-company/pdf-editor-sdk.git"
}
}
npm install vue@^3.4.0 pinia@^2.1.0
# or
yarn add vue@^3.4.0 pinia@^2.1.0
<!-- A. CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus/dist/index.css">
<!-- B. JS Dependencies -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.30/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-demi@0.14.6/lib/index.iife.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pinia@2.1.7/dist/pinia.iife.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/element-plus/dist/index.full.min.js"></script>
<!-- C. PDF Editor SDK -->
<script src="./pdf-editor-sdk.umd.js"></script>
import PDFEditorSDK from 'pdf-editor-sdk'
import 'pdf-editor-sdk/style.css'
<div id="editor-container" style="width: 100%; height: 600px;"></div>
const editor = new PDFEditorSDK({
container: '#editor-container',
width: 800,
height: 600,
onReady: () => {
console.log('Editor ready!')
},
onError: (error) => {
console.error('Editor error:', error)
}
})
// Load a PDF
await editor.loadPDF('/path/to/document.pdf')
// Add some text
editor.addText('Hello World', {
fontSize: 24,
fontFamily: 'Arial'
})
// Export to PDF
const blob = await editor.exportToPDF()
// Download or upload the blob
| Option | Type | Default | Description |
|---|---|---|---|
container |
HTMLElement | string | required | Container element or CSS selector |
width |
number | 800 | Canvas width in pixels |
height |
number | 600 | Canvas height in pixels |
theme |
'light' | 'dark' | 'light' | Color theme |
locale |
'en' | 'vi' | 'zh' | 'en' | Language |
initialPDF |
string | File | ArrayBuffer | undefined | PDF to load on init |
wasmUrl |
string | undefined | URL to pdfcore.wasm file (required) |
features |
object | all enabled | Enable/disable features |
onReady |
function | undefined | Called when ready |
onExport |
function | undefined | Called on export |
onError |
function | undefined | Called on error |
const editor = new PDFEditorSDK({
container: '#editor',
features: {
text: true, // Enable text editing
image: true, // Enable image insertion
shape: true, // Enable shape drawing
qrcode: true, // Enable QR codes
barcode: true, // Enable barcodes
signature: false, // Disable signatures
watermark: false // Disable watermarks
}
})
Returns the underlying Fabric.js canvas instance for advanced manipulation.
const canvas = editor.getCanvas()
if (canvas) {
canvas.setBackgroundColor('#f0f0f0', canvas.renderAll.bind(canvas))
}
Set the canvas zoom level (1 = 100%).
editor.setZoom(1.5) // 150% zoom
Get the current zoom level.
const currentZoom = editor.getZoom()
Automatically fit the canvas to the container size.
editor.fitToScreen()
Add a text element to the canvas.
editor.addText('My Text', {
fontSize: 32,
fontFamily: 'Helvetica',
fontWeight: 'bold',
fill: '#333333',
opacity: 1
})
Add an image from a URL.
editor.addImage('/path/to/image.jpg', {
scaleX: 0.5,
scaleY: 0.5,
opacity: 0.8
})
Generate and add a QR code.
editor.addQRCode('https://example.com', {
size: 200,
errorCorrectionLevel: 'H'
})
Generate and add a barcode.
editor.addBarCode('123456789', {
format: 'CODE128',
displayValue: true
})
Add a semi-transparent watermark.
editor.addWatermark('CONFIDENTIAL', {
fontSize: 72,
opacity: 0.2,
fill: '#ff0000'
})
Delete currently selected element(s).
Duplicate currently selected element(s).
Select all elements on the canvas.
Deselect all elements.
editor.selectAll()
editor.duplicateSelected()
editor.clearSelection()
Load a PDF file from various sources.
// From URL
await editor.loadPDF('/documents/sample.pdf')
// From File input
const fileInput = document.querySelector('input[type="file"]')
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0]
await editor.loadPDF(file)
})
Get the total number of pages.
Navigate to a specific page (1-indexed).
Add a new blank page.
Delete a specific page.
const totalPages = editor.getPageCount()
console.log(`Total pages: ${totalPages}`)
editor.goToPage(2) // Go to page 2
editor.addPage() // Add new page
Export the document as PDF.
const pdfBlob = await editor.exportToPDF({
pages: 'all', // 'all', 'current', or [1, 2, 3]
quality: 1,
dpi: 300
})
// Download the PDF
const url = URL.createObjectURL(pdfBlob)
const a = document.createElement('a')
a.href = url
a.download = 'document.pdf'
a.click()
Export as PNG image.
const pngBlob = await editor.exportToPNG({
quality: 1,
dpi: 150
})
Export as JPEG image.
const jpegBlob = await editor.exportToJPEG({
quality: 0.9,
dpi: 72
})
Mount the editor to the DOM (if unmounted).
Unmount the editor from the DOM without destroying it.
Completely destroy the editor and cleanup resources.
// Cleanup on component unmount
onBeforeUnmount(() => {
editor.destroy()
})
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="pdf-editor-sdk.css">
</head>
<body>
<div id="editor"></div>
<!-- Load peer dependencies first -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.30/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pinia@2.1.7/dist/pinia.iife.prod.js"></script>
<!-- Load SDK (UMD build for browser) -->
<script src="./pdf-editor-sdk.umd.js"></script>
<script>
// Access SDK from global variable
const PDFEditorSDK = window.PDFEditorSDK?.default || window.PDFEditorSDK
const editor = new PDFEditorSDK({
container: '#editor',
width: 800,
height: 600,
onReady: () => {
console.log('Ready!')
}
})
</script>
</body>
</html>
<template>
<div>
<div ref="editorContainer"></div>
<button @click="addText">Add Text</button>
<button @click="exportPDF">Export PDF</button>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import PDFEditorSDK from 'pdf-editor-sdk'
import 'pdf-editor-sdk/style.css'
const editorContainer = ref(null)
let editor = null
onMounted(() => {
editor = new PDFEditorSDK({
container: editorContainer.value,
width: 800,
height: 600
})
})
const addText = () => {
editor?.addText('Hello from Vue!')
}
const exportPDF = async () => {
const blob = await editor?.exportToPDF()
// Handle blob...
}
onBeforeUnmount(() => {
editor?.destroy()
})
</script>
import React, { useEffect, useRef } from 'react'
import PDFEditorSDK from 'pdf-editor-sdk'
import 'pdf-editor-sdk/style.css'
function PDFEditor() {
const containerRef = useRef(null)
const editorRef = useRef(null)
useEffect(() => {
if (containerRef.current) {
editorRef.current = new PDFEditorSDK({
container: containerRef.current,
width: 800,
height: 600
})
}
return () => {
editorRef.current?.destroy()
}
}, [])
const handleAddText = () => {
editorRef.current?.addText('Hello from React!')
}
return (
<div>
<div ref={containerRef}></div>
<button onClick={handleAddText}>Add Text</button>
</div>
)
}
export default PDFEditor
<input type="file" id="pdfUpload" accept=".pdf">
<script>
document.getElementById('pdfUpload')
.addEventListener('change', async (e) => {
const file = e.target.files[0]
if (file) {
try {
await editor.loadPDF(file)
console.log('PDF loaded successfully')
} catch (error) {
console.error('Error loading PDF:', error)
}
}
})
</script>
You can style the editor container to fit your application's design:
.pdf-editor-wrapper {
border: 2px solid #e5e7eb;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
background: #ffffff;
}
.pdf-editor-wrapper canvas {
cursor: crosshair;
}
Apply dark theme styles:
const editor = new PDFEditorSDK({
container: '#editor',
theme: 'dark'
})
/* Custom dark theme CSS */
.pdf-editor-wrapper[data-theme="dark"] {
background: #1f2937;
color: #f3f4f6;
}
<style>
@media (max-width: 768px) {
.pdf-editor-wrapper {
width: 100% !important;
height: 100vh !important;
}
}
</style>
<script>
// Auto-resize on window resize
window.addEventListener('resize', () => {
editor.fitToScreen()
})
</script>
Solution: Ensure the container element exists in the DOM before initializing the SDK. If using a framework, make sure to initialize in the mounted/useEffect hook.
Solution: Check that you've imported the CSS file and that the container has a defined width and height.
Solution: Verify the PDF file is accessible (not blocked by CORS). For cross-origin PDFs, ensure proper CORS headers are set on the server.
Solution: Wait for the editor to be ready (use onReady callback) before calling export methods. Large documents may take time to process.
| Browser | Version | Support |
|---|---|---|
| Chrome | 90+ | ✅ Full Support |
| Firefox | 88+ | ✅ Full Support |
| Safari | 14+ | ✅ Full Support |
| Edge | 90+ | ✅ Full Support |
// Access internal canvas for debugging
const canvas = editor.getCanvas()
console.log('Canvas objects:', canvas.getObjects())
console.log('Active object:', canvas.getActiveObject())
// Listen to canvas events
canvas.on('object:added', (e) => {
console.log('Object added:', e.target)
})