webdevpuneet.com

pdf-lib Merge and Reorder PDFs in the Browser — Free JavaScript Snippet

pdf-lib Merge and Reorder PDFs in the Browser · Tools · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="pm">
  <header class="pm-head">
    <div>
      <h2>Merge PDFs</h2>
      <p>Files never leave your browser. Add PDFs, put them in order, merge.</p>
    </div>
    <div class="pm-add">
      <label class="pm-file">Add PDFs<input type="file" id="pmFiles" accept="application/pdf" multiple></label>
      <button type="button" id="pmSamples" class="ghost">Add 3 sample PDFs</button>
    </div>
  </header>
  <div class="pm-drop" id="pmDrop">Drop PDF files here</div>
  <ol class="pm-list" id="pmList" aria-label="Files to merge"></ol>
  <div class="pm-bar">
    <button type="button" id="pmMerge" disabled>Merge</button>
    <button type="button" id="pmDownload" class="ghost" disabled>Download merged PDF</button>
    <span id="pmStatus" role="status"></span>
  </div>
  <div class="pm-pages" id="pmPages" aria-label="Pages of the merged PDF"></div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

100% client-side
Files never leave the browser.
Drag and drop
Plus a standard multi-file picker.
Up-front validation
Invalid files reported with the reason.
Reorder and remove
Keyboard-accessible buttons.
copyPages merging
Fonts and images carried across files.
Page thumbnails
PDF.js renders the merged result.
Generated samples
Works with no files or network.
Metadata
Title and producer set on the output.

About this UI Snippet

Merge PDFs Client-Side With pdf-lib — Private, Fast, No Server

Screenshot of the pdf-lib Merge and Reorder PDFs in the Browser snippet rendered live

"Merge these PDFs" is one of the most common document tasks, and most online tools do it by uploading your files to a server. With pdf-lib the whole job can run in the browser: files are read locally, merged in memory, and downloaded without leaving the device. That matters for contracts, medical documents or anything else private.

Reading files

Files come from a file input or drag and drop. file.arrayBuffer() gives the raw bytes, which are loaded with PDFDocument.load. Loading up front validates the file — a corrupt or non-PDF file is reported instead of failing at merge time — and gives the page count for the list.

The merge is copyPages

A new empty document is created with PDFDocument.create(). For each source file, in the chosen order, out.copyPages(src, src.getPageIndices()) copies every page, then each is added with addPage. copyPages doesn't just copy drawing instructions: it brings along every resource a page references — fonts, images, colour spaces — which is what makes merging unrelated files work. Metadata such as the title is set on the output before save() returns the bytes.

Seeing the result

After merging, PDF.js renders a thumbnail of every page, so you can check the order before downloading. Because PDF.js detaches the buffer it's given, it receives a copy; the original bytes stay available for the download.

Sample files without network

"Add 3 sample PDFs" generates three small documents with pdf-lib itself — coloured headers and page numbers — so the demo is fully usable without your own files.

Limits

Everything is held in memory, which is fine for typical documents but not for gigabyte archives. Encrypted PDFs can't be loaded without their password. Links and form fields within pages are copied, but a document-level outline (bookmarks) isn't merged.

Step by step

How to Use

  1. 1
    Add filesPick or drop PDFs, or press "Add 3 sample PDFs".
  2. 2
    Order themUse the arrow buttons; remove files with ✕.
  3. 3
    MergePages are copied into one new document in list order.
  4. 4
    Check the pagesThumbnails of every merged page appear below.
  5. 5
    DownloadSaves merged.pdf (open the demo in its own tab if the sandbox blocks it).

Real-world uses

Common Use Cases

Job application packs
Combine a cover letter, CV and portfolio into one PDF with drag-and-drop ordering, so a recruiter opens a single tidy file instead of three separate attachments.
Contracts and HR paperwork
Merge signed pages, ID copies and forms without uploading them anywhere. The files never leave the browser, which matters for contracts and medical documents.
Study notes and assignment bundles
Let students join lecture notes into one revision file or combine submission pages. Preview every page with PDF.js before downloading to confirm the order.
Internal tools without a backend
Add batch merging to an admin panel with no server code. Invalid files are reported up front with the reason, so staff know which document to replace.
Privacy-first document apps
Offer PDF merging as a selling point: nothing is sent to a third-party service, and keyboard-accessible reorder buttons keep the tool usable without a mouse.
Related: pdf-lib Watermark and Page Numbers
Stamp the merged file: pdf-lib Watermark and Page Numbers.
Related: File Dropzone
A styled drop target: File Dropzone Uploader.

Got questions?

Frequently Asked Questions

Create an empty document with PDFDocument.create(). For each source, load it with PDFDocument.load(bytes), copy its pages with out.copyPages(src, src.getPageIndices()), and add each copied page with out.addPage(page). Finally call out.save() to get the merged bytes.

No. Files are read with the File API and processed in memory by pdf-lib in the browser. Nothing is sent to a server.

Yes. Pass an array of page indexes to copyPages instead of getPageIndices(), for example [0, 2, 3] to copy the first, third and fourth pages.

A page belongs to its document and references objects such as fonts and images stored there. copyPages creates copies of the page and all its referenced objects in the target document.

pdf-lib cannot decrypt password-protected files. It will throw when loading them unless you pass ignoreEncryption, which only works for files that are encrypted but openable without a password, and the output may not be usable.