How to Sign PDF Files in the Browser with Vue 3 and pdf-lib

javascript dev.to

Signing PDFs in the browser involves capturing user input and embedding it into the PDF document. Here's how to build a browser-based PDF signing tool with Vue 3 and pdf-lib.

The challenge: Signature capture and placement

PDF signing requires:

  1. Capturing handwritten signatures via canvas
  2. Converting signatures to images
  3. Positioning signatures on specific pages
  4. Preserving signature appearance and quality

The stack

  • Vue 3 with Composition API
  • pdf-lib for PDF manipulation
  • Canvas API for signature drawing
  • Vite for bundling

The core implementation

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { PDFDocument } from 'pdf-lib'

const file = ref<File | null>(null)
const signatureImage = ref<string | null>(null)
const isDrawing = ref(false)
const signing = ref(false)
const result = ref<Uint8Array | null>(null)

const canvasRef = ref<HTMLCanvasElement | null>(null)
let ctx: CanvasRenderingContext2D | null = null

function startDrawing(e: MouseEvent | TouchEvent) {
  isDrawing.value = true
  draw(e)
}

function stopDrawing() {
  isDrawing.value = false
}

function draw(e: MouseEvent | TouchEvent) {
  if (!isDrawing.value || !ctx) return

  const canvas = canvasRef.value!
  const rect = canvas.getBoundingClientRect()

  let x, y
  if (e instanceof MouseEvent) {
    x = e.clientX - rect.left
    y = e.clientY - rect.top
  } else {
    x = e.touches[0].clientX - rect.left
    y = e.touches[0].clientY - rect.top
  }

  ctx.lineTo(x, y)
  ctx.stroke()
}

function clearCanvas() {
  if (ctx && canvasRef.value) {
    ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height)
  }
}

async function signPdf() {
  if (!file.value || !signatureImage.value) return
  signing.value = true

  // Convert canvas to image data URL
  const canvas = canvasRef.value!
  signatureImage.value = canvas.toDataURL('image/png')

  const arrayBuffer = await file.value.arrayBuffer()
  const pdf = await PDFDocument.load(arrayBuffer)
  const pages = pdf.getPages()
  const page = pages[0]

  const signatureBytes = await fetch(signatureImage.value)
    .then(res => res.arrayBuffer())

  const pngImage = await pdf.embedPng(signatureBytes)

  page.drawImage(pngImage, {
    x: 50,
    y: 100,
    width: 200,
    height: 60,
  })

  result.value = await pdf.save()
  signing.value = false
}
</script>
Enter fullscreen mode Exit fullscreen mode

Key implementation details

1. Canvas signature capture

Use Canvas API to capture handwritten signatures:

const canvas = document.createElement('canvas')
canvas.width = 400
canvas.height = 150
const ctx = canvas.getContext('2d')!

ctx.strokeStyle = '#000'
ctx.lineWidth = 2
ctx.lineCap = 'round'
Enter fullscreen mode Exit fullscreen mode

2. Touch and mouse events

Support both mouse and touch input:

canvas.addEventListener('mousedown', startDrawing)
canvas.addEventListener('mousemove', draw)
canvas.addEventListener('mouseup', stopDrawing)
canvas.addEventListener('mouseout', stopDrawing)

// Touch events
canvas.addEventListener('touchstart', startDrawing)
canvas.addEventListener('touchmove', draw)
canvas.addEventListener('touchend', stopDrawing)
Enter fullscreen mode Exit fullscreen mode

3. Signature to image conversion

Convert canvas drawing to PNG for embedding:

const signatureDataUrl = canvas.toDataURL('image/png')
const response = await fetch(signatureDataUrl)
const arrayBuffer = await response.arrayBuffer()
const pngImage = await pdf.embedPng(arrayBuffer)
Enter fullscreen mode Exit fullscreen mode

4. Positioning the signature

Place signature at specific coordinates:

page.drawImage(pngImage, {
  x: 50,    // Left margin
  y: 100,   // Bottom position
  width: 200,
  height: 60,
})
Enter fullscreen mode Exit fullscreen mode

Limitations

No real-time preview

Can't show signature placement before applying.

Solution: Use a separate preview canvas.

Limited signature styles

Basic drawing only; no fonts or styles.

Solution: Support image upload for more options.

Mobile compatibility

Touch events need careful handling.

Solution: Test on multiple devices.

Summary

Building a browser-based PDF signing tool involves:

  1. Creating a canvas for signature drawing
  2. Capturing user input (mouse/touch)
  3. Converting signature to image
  4. Embedding in PDF at specified position

Try it at en.sotool.top/sign-pdf.

Source: dev.to

arrow_back Back to Tutorials