DEV Community

sunshey
sunshey

Posted on

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

Combining multiple PDFs into one seems simple, but there are important considerations around file ordering and memory management. Here's how to build a browser-based PDF merge tool with Vue 3 and pdf-lib.

The challenge: Managing multiple documents

When merging PDFs, you need to:

  1. Load multiple PDF files in the browser
  2. Display thumbnails for ordering
  3. Merge page streams without losing content
  4. Handle large files without crashing

The stack

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

The core implementation

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

const files = ref<File[]>([])
const merging = ref(false)
const result = ref<Uint8Array | null>(null)

async function mergePdfs() {
  if (files.value.length === 0) return
  merging.value = true

  const mergedPdf = await PDFDocument.create()

  for (const file of files.value) {
    const arrayBuffer = await file.arrayBuffer()
    const pdf = await PDFDocument.load(arrayBuffer)
    const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices())
    pages.forEach(page => mergedPdf.addPage(page))
  }

  result.value = await mergedPdf.save()
  merging.value = false
}

function reorderFiles(fromIndex: number, toIndex: number) {
  const updated = [...files.value]
  const [removed] = updated.splice(fromIndex, 1)
  updated.splice(toIndex, 0, removed)
  files.value = updated
}
</script>
Enter fullscreen mode Exit fullscreen mode

Key implementation details

1. Loading multiple PDFs

Use the File API to read each file as an ArrayBuffer:

const arrayBuffer = await file.arrayBuffer()
const pdf = await PDFDocument.load(arrayBuffer)
Enter fullscreen mode Exit fullscreen mode

2. Copying pages between PDFs

pdf-lib requires explicit page copying:

const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices())
pages.forEach(page => mergedPdf.addPage(page))
Enter fullscreen mode Exit fullscreen mode

3. Drag-and-drop reordering

Implement a simple index-based reorder:

function reorderFiles(fromIndex: number, toIndex: number) {
  const updated = [...files.value]
  const [removed] = updated.splice(fromIndex, 1)
  updated.splice(toIndex, 0, removed)
  files.value = updated
}
Enter fullscreen mode Exit fullscreen mode

4. Memory management

For large files, process sequentially:

for (const file of files.value) {
  const pdf = await PDFDocument.load(await file.arrayBuffer())
  const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices())
  pages.forEach(page => mergedPdf.addPage(page))
}
Enter fullscreen mode Exit fullscreen mode

Limitations

No undo

Once merged, files cannot be separated.

Solution: Always keep backups of original files.

Large files

Very large PDFs may cause memory issues in the browser.

Solution: Process files in smaller batches or use Web Workers.

Password-protected PDFs

Encrypted PDFs cannot be merged without the password.

Solution: Remove encryption first.

Summary

Building a browser-based PDF merge tool involves:

  1. Loading multiple PDFs with the File API
  2. Copying pages between PDFDocument instances
  3. Providing drag-and-drop reordering
  4. Saving and downloading the merged result

Try it at en.sotool.top/merge.

Top comments (0)