How to Add Page Numbers to PDF in the Browser with Vue 3 and pdf-lib

javascript dev.to

Adding page numbers to PDFs in the browser involves positioning text correctly and handling different page layouts. Here's how to build a browser-based PDF page numbering tool with Vue 3 and pdf-lib.

The challenge: Positioning and formatting

Page number implementation requires:

  1. Calculating correct X/Y coordinates for different positions
  2. Supporting various formats (1, 2, 3 or 1 of 10, Page 1, etc.)
  3. Handling different page sizes (A4, Letter, etc.)
  4. Applying consistent styling across all pages

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, rgb, StandardFonts } from 'pdf-lib'

type Position = 'top-left' | 'top-center' | 'top-right' | 
               'bottom-left' | 'bottom-center' | 'bottom-right'

const file = ref<File | null>(null)
const position = ref<Position>('bottom-center')
const format = ref<'simple' | 'of-total' | 'page-prefix'>('simple')
const fontSize = ref(12)
const startingNumber = ref(1)
const numbering = ref(false)
const result = ref<Uint8Array | null>(null)

async function addPageNumbers() {
  if (!file.value) return
  numbering.value = true

  const arrayBuffer = await file.value.arrayBuffer()
  const pdf = await PDFDocument.load(arrayBuffer)
  const pages = pdf.getPages()
  const font = await pdf.embedFont(StandardFonts.Helvetica)

  const totalPages = pages.length
  const margin = 50

  for (let i = 0; i < totalPages; i++) {
    const page = pages[i]
    const { width, height } = page.getSize()
    const pageNum = i + startingNumber.value

    let text = format.value === 'simple' 
      ? String(pageNum)
      : format.value === 'of-total'
      ? `${pageNum} / ${totalPages}`
      : `Page ${pageNum}`

    let x: number
    let y: number

    switch (position.value) {
      case 'top-left':
        x = margin
        y = height - margin - fontSize.value
        break
      case 'top-center':
        x = (width - 50) / 2
        y = height - margin - fontSize.value
        break
      case 'top-right':
        x = width - margin - 50
        y = height - margin - fontSize.value
        break
      case 'bottom-left':
        x = margin
        y = margin
        break
      case 'bottom-center':
        x = (width - 50) / 2
        y = margin
        break
      case 'bottom-right':
        x = width - margin - 50
        y = margin
        break
    }

    page.drawText(text, {
      x,
      y,
      size: fontSize.value,
      font,
      color: rgb(0, 0, 0),
    })
  }

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

Key implementation details

1. Position calculation

Calculate coordinates based on page dimensions and margins:

const margin = 50
switch (position) {
  case 'bottom-center':
    x = (width - textWidth) / 2
    y = margin
    break
  // ... other positions
}
Enter fullscreen mode Exit fullscreen mode

2. Format options

Support different numbering formats:

const text = format === 'simple' 
  ? String(pageNum)
  : format === 'of-total'
  ? `${pageNum} / ${totalPages}`
  : `Page ${pageNum}`
Enter fullscreen mode Exit fullscreen mode

3. Starting number

Allow customization of the starting page number:

const pageNum = i + startingNumber.value
Enter fullscreen mode Exit fullscreen mode

4. Font embedding

Always embed fonts for consistent rendering:

const font = await pdf.embedFont(StandardFonts.Helvetica)
Enter fullscreen mode Exit fullscreen mode

Limitations

No preview without rendering

pdf-lib doesn't provide real-time preview of page numbers.

Solution: Show a static preview or render thumbnails separately.

Limited formatting options

Basic text positioning only; no headers/footers with images.

Solution: Use desktop software for complex formatting.

Page size variations

Different page sizes require position adjustments.

Solution: Calculate positions dynamically based on page dimensions.

Summary

Building a browser-based PDF page numbering tool involves:

  1. Loading the PDF with pdf-lib
  2. Calculating position coordinates for each page
  3. Drawing page numbers with the correct format
  4. Saving and downloading the numbered PDF

Try it at en.sotool.top/page-numbers.

Source: dev.to

arrow_back Back to Tutorials