👉 Try Free Online Marksheet Generator Tool – Create school & college marksheets instantly

Build a PDF Editor in Browser Using PDF-LIB Library

The Portable Document Format (PDF) is the de facto standard for sharing documents, but for a long time, creating and manipulating them on the web has been a server-side affair. That's no longer the case. Thanks to powerful libraries like pdf-lib.js, you can now build sophisticated PDF tools that run entirely in the user's browser. This guide will walk you through creating a complete, browser-based PDF editor from scratch.

What You'll Build: A web application that allows users to upload a PDF, add text to any page, and download the modified file. We'll cover everything from setting up the project to handling file manipulation and saving.

Why `pdf-lib.js`?

While other libraries like jsPDF are excellent for generating PDFs from scratch, `pdf-lib.js` excels at both creating new documents and, more importantly, modifying existing ones. Its API is intuitive and robust, allowing you to:

This makes it the perfect choice for building an editor where users can interact with and modify existing PDF files.

Project Setup: The HTML Foundation

First, we need an HTML file to serve as the foundation of our application. This file will contain the user interface (UI) elements for our editor and the necessary script tags to include `pdf-lib` and Prism.js for code highlighting.

We'll include the `pdf-lib.js` library from a CDN. We'll also include Prism.js for syntax highlighting, along with its line-number and copy-to-clipboard plugins to make the code easy to read and use.

Building the User Interface

The UI for our editor will be simple but effective. We need:

The JavaScript Logic: Bringing the Editor to Life

This is where the magic happens. We'll write JavaScript code to handle the following tasks:

  1. Loading the PDF: We'll get the uploaded file from the input and read it into an `ArrayBuffer`.
  2. Initializing `pdf-lib`: We'll load the `ArrayBuffer` into `pdf-lib` to create a `PDFDocument` object.
  3. Modifying the Page: We'll get the specific page the user wants to edit, embed a standard font, and draw the user's text at the specified coordinates.
  4. Saving the PDF: Finally, we'll serialize the modified `PDFDocument` back into a `Uint8Array` and create a downloadable link for the user.

Explaining the Core `modifyPdf` Function

The heart of our editor is the `modifyPdf` function. Let's break down its key parts.

Loading the Document

First, we load the raw PDF data into a `PDFDocument` object. This object is our gateway to interacting with the PDF's content.


const pdfDoc = await PDFDocument.load(existingPdfBytes);
        

Embedding a Font

To draw text, we need a font. `pdf-lib` allows you to embed custom fonts, but for simplicity, we'll use one of the standard fonts that all PDF viewers support.


const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica);
        

Accessing the Page

We get an array of all the pages in the document and then access the specific page the user wants to edit. Remember that pages are zero-indexed, so we subtract 1 from the user's input.


const pages = pdfDoc.getPages();
const page = pages[pageNumber - 1]; // Page numbers are 1-based in UI
        

Drawing the Text

This is where we perform the actual modification. We use the `page.drawText` method, providing the text, coordinates, font, and size. A crucial detail is the coordinate system: `pdf-lib`'s origin `(0, 0)` is at the bottom-left corner of the page, not the top-left like in most browser contexts.


page.drawText(textToAdd, {
    x: x,
    y: y,
    font: helveticaFont,
    size: 24,
    color: rgb(0.95, 0.1, 0.1),
});
        

Saving the Result

After modifying the document, we save it. This converts the `PDFDocument` object into a `Uint8Array`, which is a binary representation of the PDF file.


const pdfBytes = await pdfDoc.save();
        

This `Uint8Array` can then be used to create a `Blob` and generate a URL for downloading.

Putting It All Together: The Full Code

Here is the complete code for our browser-based PDF editor. You can save this as a single HTML file and open it in your web browser to run the application.


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PDF Editor with pdf-lib.js</title>
    <script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"></script>
    <style>
        body { font-family: sans-serif; padding: 2em; }
        .container { max-width: 800px; margin: auto; }
        .form-group { margin-bottom: 1em; }
        label { display: block; margin-bottom: .5em; }
        input[type="text"], input[type="number"], input[type="file"] { width: 100%; padding: .5em; }
        button { padding: .7em 1.5em; cursor: pointer; }
    </style>
</head>
<body>
    <div class="container">
        <h1>Browser-Based PDF Editor</h1>
        
        <div class="form-group">
            <label for="pdfFile">Upload PDF:</label>
            <input type="file" id="pdfFile" accept=".pdf">
        </div>

        <div class="form-group">
            <label for="textToAdd">Text to Add:</label>
            <input type="text" id="textToAdd" placeholder="Enter text...">
        </div>

        <div class="form-group">
            <label for="pageNumber">Page Number:</label>
            <input type="number" id="pageNumber" value="1" min="1">
        </div>
        
        <div class="form-group">
            <label for="xCoord">X Coordinate:</label>
            <input type="number" id="xCoord" value="50">
        </div>

        <div class="form-group">
            <label for="yCoord">Y Coordinate:</label>
            <input type="number" id="yCoord" value="50">
        </div>

        <button id="modifyBtn">Add Text to PDF</button>

        <div class="form-group" style="margin-top: 2em;">
            <a id="downloadLink" style="display:none;">Download Modified PDF</a>
        </div>
    </div>

    <script>
        const { PDFDocument, rgb, StandardFonts } = PDFLib;

        const fileInput = document.getElementById('pdfFile');
        const modifyBtn = document.getElementById('modifyBtn');
        const downloadLink = document.getElementById('downloadLink');
        let pdfBytes = null;

        fileInput.addEventListener('change', async (e) => {
            if (e.target.files.length > 0) {
                const file = e.target.files[0];
                pdfBytes = await file.arrayBuffer();
                console.log("PDF loaded.");
            }
        });

        modifyBtn.addEventListener('click', async () => {
            if (!pdfBytes) {
                alert("Please upload a PDF file first.");
                return;
            }

            const textToAdd = document.getElementById('textToAdd').value;
            const pageNumber = parseInt(document.getElementById('pageNumber').value);
            const x = parseInt(document.getElementById('xCoord').value);
            const y = parseInt(document.getElementById('yCoord').value);

            if (!textToAdd) {
                alert("Please enter text to add.");
                return;
            }

            try {
                const modifiedPdfBytes = await modifyPdf(pdfBytes, textToAdd, pageNumber, x, y);
                
                const blob = new Blob([modifiedPdfBytes], { type: 'application/pdf' });
                const url = URL.createObjectURL(blob);
                
                downloadLink.href = url;
                downloadLink.download = 'modified.pdf';
                downloadLink.style.display = 'block';
                
                alert("PDF modified successfully! Click the download link.");

            } catch (error) {
                console.error(error);
                alert("Failed to modify PDF. Check console for details.");
            }
        });

        async function modifyPdf(existingPdfBytes, textToAdd, pageNumber, x, y) {
            // Load a PDFDocument from the existing PDF bytes
            const pdfDoc = await PDFDocument.load(existingPdfBytes);

            // Embed the Helvetica font
            const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica);

            // Get the page to modify
            const pages = pdfDoc.getPages();
            if (pageNumber > pages.length || pageNumber < 1) {
                throw new Error(`Invalid page number: ${pageNumber}. PDF has ${pages.length} pages.`);
            }
            const page = pages[pageNumber - 1]; // pdf-lib pages are 0-indexed

            // Draw a string of text diagonally across the first page
            page.drawText(textToAdd, {
                x: x,
                y: y,
                font: helveticaFont,
                size: 24,
                color: rgb(0.95, 0.1, 0.1),
            });

            // Serialize the PDFDocument to bytes (a Uint8Array)
            const pdfBytes = await pdfDoc.save();
            return pdfBytes;
        }
    </script>
</body>
</html>
        

Conclusion & Next Steps

You've just built a fully functional, client-side PDF editor! This is a powerful starting point. From here, you could expand the functionality in numerous ways:

By leveraging `pdf-lib.js`, you've unlocked the ability to create rich, interactive PDF experiences directly in the browser, opening up a world of possibilities for your web applications.