DEV Community

sunshey
sunshey

Posted on

How to Crop PDF Pages in the Browser with Vue 3 and pdf-lib

Cropping PDF pages sounds like a server-side operation, but with pdf-lib and a <canvas> preview, you can do it entirely in the browser. No upload, no backend, and full control over margins.

This post walks through a minimal but production-ready implementation you can drop into a Vue 3 project.

Why client-side?

Traditional PDF croppers upload your file, crop it on a server, and send it back. That works, but it introduces latency, bandwidth costs, and privacy risk. A browser-based cropper:

  • Keeps files on the user's device
  • Works offline after the app loads
  • Avoids server-side processing entirely

The stack

  • Vue 3 with Composition API
  • pdf-lib for PDF manipulation
  • PDF.js for page preview rendering
  • Canvas for interactive crop region selection
  • Vite for bundling

Minimal implementation

<script setup lang="ts">
import { ref } from 'vue'
import { PDFDocument, rgb } from 'pdf-lib'
import * as pdfjs from 'pdfjs-dist'

pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js'

const file = ref<File | null>(null)
const cropping = ref(false)
const margins = ref({ top: 50, bottom: 50, left: 50, right: 50 })

async function handleFileUpload(selected: File) {
  file.value = selected
}

async function cropPdf() {
  if (!file.value) return
  cropping.value = true

  try {
    const arrayBuffer = await file.value.arrayBuffer()
    const pdf = await PDFDocument.load(arrayBuffer)
    const pages = pdf.getPages()

    for (const page of pages) {
      const { width, height } = page.getSize()
      const m = margins.value

      // Clamp margins to page dimensions
      const cropLeft = Math.min(m.left, width / 2 - 1)
      const cropRight = Math.min(m.right, width / 2 - 1)
      const cropTop = Math.min(m.top, height / 2 - 1)
      const cropBottom = Math.min(m.bottom, height / 2 - 1)

      page.setCropBox(
        cropLeft,
        cropBottom,
        width - cropLeft - cropRight,
        height - cropTop - cropBottom
      )
    }

    const croppedBytes = await pdf.save()
    const blob = new Blob([croppedBytes], { type: 'application/pdf' })
    downloadBlob(blob, 'cropped.pdf')
  } finally {
    cropping.value = false
  }
}

function downloadBlob(blob: Blob, name: string) {
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = name
  a.click()
  URL.revokeObjectURL(url)
}
</script>
Enter fullscreen mode Exit fullscreen mode

The key method is page.setCropBox(left, bottom, width, height). It modifies the crop box — the visible area when the page is displayed. Unlike the media box (physical page size), the crop box doesn't change the underlying content; it just hides what's outside the visible region.

Interactive crop preview

For a better UX, render the page with PDF.js on a canvas and draw an overlay rectangle showing the crop region. Users can drag the edges of the rectangle to adjust margins visually:

function drawCropOverlay(canvas: HTMLCanvasElement, page: pdfjs.PageViewport) {
  const ctx = canvas.getContext('2d')!
  ctx.clearRect(0, 0, canvas.width, canvas.height)

  // Draw the page
  page.draw(ctx).promise.then(() => {
    // Draw semi-transparent overlay outside crop region
    ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'
    const m = margins.value
    // Top strip
    ctx.fillRect(0, 0, canvas.width, canvas.height * (m.top / page.height))
    // Bottom strip
    ctx.fillRect(0, canvas.height * ((page.height - m.bottom) / page.height), canvas.width, canvas.height * (m.bottom / page.height))
    // Left strip
    ctx.fillRect(0, canvas.height * (m.top / page.height), canvas.width * (m.left / page.width), canvas.height * (1 - (m.top + m.bottom) / page.height))
    // Right strip
    ctx.fillRect(canvas.width * ((page.width - m.right) / page.width), canvas.height * (m.top / page.height), canvas.width * (m.right / page.width), canvas.height * (1 - (m.top + m.bottom) / page.height))
  })
}
Enter fullscreen mode Exit fullscreen mode

UX tips from a live tool

At en.sotool.top/crop-pdf, we learned a few things from real users:

  1. Provide presets. Most users just want to remove scan borders. Give them a one-click solution.
  2. Allow page-specific settings. Not every page in a document has the same margins.
  3. Show a before/after preview. Users need to see the result before downloading.
  4. Explain the difference between crop and trim. Crop hides content; trim destroys it.

Going further

For simple PDF cropping, pdf-lib plus a canvas preview is enough. If you need batch processing, OCR, or conversion to editable formats, you'll want a desktop tool.

Want to see the full source? The site is built in public at github.com/sunshey/pdf-tool.


If you need desktop-grade PDF editing — OCR, batch cropping, or advanced export formats — check out Wondershare PDFelement.

Top comments (0)