How I Split PDFs in the Browser with Vue 3 and pdf-lib

Splitting a PDF is one of those features that sounds trivial until you try to build it. Users expect range input (1-3, 5, 7-9), a per-page option, multiple file downloads, and zero server involvement.

I built en.sotool.top/split/ to do exactly that. H…


This content originally appeared on DEV Community and was authored by sunshey

Splitting a PDF is one of those features that sounds trivial until you try to build it. Users expect range input (1-3, 5, 7-9), a per-page option, multiple file downloads, and zero server involvement.

I built en.sotool.top/split/ to do exactly that. Here's how it works with Vue 3 and pdf-lib.

Why Client-Side?

PDFs often contain sensitive information. Contracts, medical records, financial statements. Even a "simple" splitting tool should not force users to upload files to a server.

Client-side benefits:

  • No upload bandwidth or size limits
  • No server storage or cleanup
  • Instant processing for normal files
  • Works offline after the page loads

The tradeoff is that everything has to run in the browser, which limits the libraries you can use.

The Stack

  • Vue 3 — UI and state
  • pdf-lib — Load, manipulate, and save PDFs
  • File API — Read the uploaded file
  • lucide-vue-next — Icons
npm install pdf-lib

Loading the PDF and Counting Pages

First, read the file into an ArrayBuffer and load it with pdf-lib.

import { PDFDocument } from 'pdf-lib'

const pdfFile = ref<File | null>(null)
const totalPages = ref(0)

async function handleFile(files: File[]) {
  if (files.length === 0) return
  pdfFile.value = files[0]
  const bytes = await files[0].arrayBuffer()
  const pdf = await PDFDocument.load(bytes)
  totalPages.value = pdf.getPageCount()
}

Now we know how many pages exist and can show the split UI.

Two Split Modes

I offer two ways to split: by range and per page.

Mode 1: Page Range Input

Users type something like 1-3, 5, 7-9. I parse it into groups of page indices.

function parseRanges(input: string, max: number): number[][] {
  const groups: number[][] = []
  const parts = input.split(',').map(s => s.trim())

  for (const part of parts) {
    if (part.includes('-')) {
      const [start, end] = part.split('-').map(Number)
      const pages = []
      for (let i = start; i <= end && i <= max; i++) {
        pages.push(i - 1)
      }
      if (pages.length) groups.push(pages)
    } else {
      const n = Number(part)
      if (n >= 1 && n <= max) groups.push([n - 1])
    }
  }

  return groups
}

This handles ranges, single pages, and mixed input. Page numbers are 1-based because that is what users expect. Internal indices are 0-based for pdf-lib.

Mode 2: Per Page

Save every page as its own PDF. This is useful when each page is effectively a separate document.

Splitting with pdf-lib

Once we know which pages go where, the logic is:

  1. Load the original PDF
  2. For each output group, create a new empty PDF
  3. Copy the relevant pages
  4. Save and download
async function splitPdf() {
  if (!pdfFile.value) return

  const bytes = await pdfFile.value.arrayBuffer()
  const pdf = await PDFDocument.load(bytes)
  const pageCount = pdf.getPageCount()

  if (splitMode.value === 'size') {
    for (let i = 0; i < pageCount; i++) {
      const newPdf = await PDFDocument.create()
      const [page] = await newPdf.copyPages(pdf, [i])
      newPdf.addPage(page)
      const blob = new Blob([await newPdf.save()], { type: 'application/pdf' })
      downloadBlob(blob, `page_${i + 1}.pdf`)
    }
  } else {
    const ranges = parseRanges(rangeInput.value, pageCount)
    for (let idx = 0; idx < ranges.length; idx++) {
      const newPdf = await PDFDocument.create()
      const pages = await newPdf.copyPages(pdf, ranges[idx])
      pages.forEach(p => newPdf.addPage(p))
      const blob = new Blob([await newPdf.save()], { type: 'application/pdf' })
      downloadBlob(blob, `split_${idx + 1}.pdf`)
    }
  }
}

copyPages preserves the content of the copied pages without re-rendering them, so quality stays intact.

Downloading the Result

A small helper to trigger a file download from a Blob.

function downloadBlob(blob: Blob, filename: string) {
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = filename
  a.click()
  URL.revokeObjectURL(url)
}

When splitting by range, this runs once per output group. When splitting per page, it runs once per page.

Lessons Learned

1-based indexing everywhere in the UI. Developers think in 0-based arrays. Users think in page numbers. Keep the internal logic 0-based but expose 1-based numbers everywhere the user sees.

Parse input defensively. Users will type 5 - 7, 5—7, or 5,6,7. Strip whitespace, handle dashes, ignore empty parts, and clamp to valid page numbers.

Allow multiple downloads. Splitting produces more than one file. Make sure your download helper works in a loop and does not block the browser.

Preserve quality with copyPages. Do not re-encode the entire PDF. Copy only the pages you need and let pdf-lib handle the rest.

Watch for browser pop-up blockers. Multiple automatic downloads can trigger the blocker. Some users may need to allow downloads from your domain.

Try It

The tool is live at en.sotool.top/split/.

Free, no signup, nothing uploads to a server.

Full source is on GitHub. The split logic is in src/views/Split.vue.

Want More Advanced PDF Tools?

If you need OCR, form editing, digital signatures, or batch processing, Wondershare PDFelement is a solid desktop option. It keeps everything local.

This post contains affiliate links.

Have you built PDF manipulation tools in the browser? What edge cases did you run into?


This content originally appeared on DEV Community and was authored by sunshey


Print Share Comment Cite Upload Translate Updates
APA

sunshey | Sciencx (2026-06-25T12:37:35+00:00) How I Split PDFs in the Browser with Vue 3 and pdf-lib. Retrieved from https://www.scien.cx/2026/06/25/how-i-split-pdfs-in-the-browser-with-vue-3-and-pdf-lib/

MLA
" » How I Split PDFs in the Browser with Vue 3 and pdf-lib." sunshey | Sciencx - Thursday June 25, 2026, https://www.scien.cx/2026/06/25/how-i-split-pdfs-in-the-browser-with-vue-3-and-pdf-lib/
HARVARD
sunshey | Sciencx Thursday June 25, 2026 » How I Split PDFs in the Browser with Vue 3 and pdf-lib., viewed ,<https://www.scien.cx/2026/06/25/how-i-split-pdfs-in-the-browser-with-vue-3-and-pdf-lib/>
VANCOUVER
sunshey | Sciencx - » How I Split PDFs in the Browser with Vue 3 and pdf-lib. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2026/06/25/how-i-split-pdfs-in-the-browser-with-vue-3-and-pdf-lib/
CHICAGO
" » How I Split PDFs in the Browser with Vue 3 and pdf-lib." sunshey | Sciencx - Accessed . https://www.scien.cx/2026/06/25/how-i-split-pdfs-in-the-browser-with-vue-3-and-pdf-lib/
IEEE
" » How I Split PDFs in the Browser with Vue 3 and pdf-lib." sunshey | Sciencx [Online]. Available: https://www.scien.cx/2026/06/25/how-i-split-pdfs-in-the-browser-with-vue-3-and-pdf-lib/. [Accessed: ]
rf:citation
» How I Split PDFs in the Browser with Vue 3 and pdf-lib | sunshey | Sciencx | https://www.scien.cx/2026/06/25/how-i-split-pdfs-in-the-browser-with-vue-3-and-pdf-lib/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.