PDF Merger UI with HTML, CSS & JavaScript
40 DAYS 40 PROJECT CHALLENGE
Day #39
Project Overview
The PDF Merger UI is a practical frontend tool built using HTML, CSS, and JavaScript. It allows users to select multiple PDF files, view the selected files in a list, remove unwanted files, and merge the remaining PDFs into a single document. The project performs the PDF processing directly in the browser with the help of the PDF-lib library, so it does not require a backend server.
First, users select two or more PDF files through the file input. Next, JavaScript stores the selected files in an array and displays their names dynamically. Users can also remove individual files before merging. Finally, the PDF-lib library loads each selected PDF, copies its pages into a new document, and creates a downloadable merged.pdf file. This project demonstrates file handling, asynchronous JavaScript, array manipulation, DOM updates, and client-side PDF processing.
Key Features
- Multiple PDF Upload: Users can select multiple PDF files at once using the file input. The project accepts only files with the PDF MIME type.
- Selected File List: Every selected PDF appears in a list below the upload field. This allows users to review the files before starting the merge process.
- Remove Individual Files: Each file in the list has an X button for removal. JavaScript removes the selected file from the array and refreshes the displayed list.
- Drag and Drop Support: The project is designed around managing the selected PDF files before merging. The file list provides a clear area for organizing the selected documents.
- Real PDF Merging: PDF-lib combines the pages from the selected PDF documents into one new PDF file. Therefore, the project performs actual PDF processing rather than simply creating a visual interface.
- Minimum File Validation: The merger checks whether at least two PDFs have been selected. If fewer than two files are available, it displays a message asking the user to select more files.
- Merge Status Updates: The interface displays messages such as “Merging PDFs…” while processing and “Download started” after creating the merged document. This gives users feedback during the operation.
- Instant PDF Download: After merging, JavaScript creates a Blob containing the new PDF and generates a temporary download URL. The final file is downloaded as
merged.pdf. - Client-Side Processing: The PDF files are processed directly in the browser using JavaScript and PDF-lib. This makes the project a useful example of browser-based file processing.
- Simple Responsive Interface: The project uses a compact centered layout with a dark theme, file list, action button, and status area. This keeps the tool simple and focused on the main PDF workflow.
What You'll Learn
- How to create a multiple-file upload interface
- How to work with JavaScript
Fileobjects - How to store selected files in an array
- How to dynamically display uploaded files
- How to remove items from an array using
splice() - How to use the PDF-lib JavaScript library
- How to work with asynchronous PDF processing
- How to create and download a Blob using JavaScript
HTML Code
The HTML creates the basic structure of the PDF Merger UI. First, it adds a main container with the PDF Merger heading and a file input that uses the multiple attribute so users can select more than one PDF. Next, an empty unordered list with the ID fileList provides the area where JavaScript displays the selected PDF names. The Merge & Download button starts the PDF merging process.
Finally, the status paragraph displays messages about the current operation, such as validation errors, the merging process, and the download status. The PDF-lib library is loaded before the JavaScript file so its PDF functions are available.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PDF Merger</title>
<link rel="stylesheet" href="style.css">
<!-- PDF-LIB CDN -->
<script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"></script>
</head>
<body>
<div class="container">
<h2>PDF Merger</h2>
<input type="file" id="fileInput" multiple accept="application/pdf">
<ul id="fileList"></ul>
<button id="mergeBtn">Merge & Download</button>
<p id="status"></p>
</div>
<script src="script.js"></script>
</body>
</html> CSS Code
The CSS creates a compact dark-themed interface. First, the body uses Flexbox to center the main container on the page and applies a dark blue background with white text. Next, the .container uses a darker background, padding, rounded corners, and a fixed width to create a simple card-style interface. The selected PDF list removes the default bullet styling and uses a maximum height with vertical scrolling when many files are added.
Each file item uses Flexbox to place the filename and Remove button on opposite sides. Finally, the main button uses a blue background and hover effect, while the status text receives spacing above it for clear feedback.
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:Arial;
}
body{
background:#0f172a;
display:flex;
justify-content:center;
align-items:center;
height:100vh;
color:#fff;
}
.container{
background:#1e293b;
padding:30px;
border-radius:12px;
width:350px;
text-align:center;
}
h2{
margin-bottom:20px;
}
input{
margin-bottom:15px;
}
ul{
list-style:none;
text-align:left;
margin-bottom:15px;
max-height:150px;
overflow-y:auto;
}
li{
background:#334155;
padding:8px;
margin-bottom:5px;
border-radius:6px;
display:flex;
justify-content:space-between;
align-items:center;
font-size:14px;
}
.remove{
background:red;
color:white;
border:none;
padding:4px 8px;
border-radius:4px;
cursor:pointer;
}
button{
width:100%;
padding:10px;
border:none;
background:#2563eb;
color:white;
border-radius:6px;
cursor:pointer;
}
button:hover{
background:#1e40af;
}
#status{
margin-top:15px;
font-size:14px;
} Javascript Code
JavaScript handles file selection, file management, PDF merging, and downloading. First, the code selects the file input, file list, merge button, and status message. It also creates a filesArray to store the selected PDF files. Next, the change event checks each selected file and adds valid PDF files to the array. The displayFiles() function then clears the existing list and dynamically creates a list item for every selected file.
After that, removeFile() uses splice() to remove a selected PDF and refreshes the list. When the Merge button is clicked, JavaScript checks that at least two files exist and then uses PDFDocument.create() to create a new PDF.
Finally, the code loads each PDF using PDFDocument.load(), copies its pages with copyPages(), and adds them to the new document. After saving the merged PDF, JavaScript creates a Blob, generates a temporary URL, and triggers the download as merged.pdf.
const { PDFDocument } = PDFLib;
const fileInput = document.getElementById("fileInput");
const fileList = document.getElementById("fileList");
const mergeBtn = document.getElementById("mergeBtn");
const statusText = document.getElementById("status");
let filesArray = [];
// Select files
fileInput.addEventListener("change", function(){
for(let file of fileInput.files){
if(file.type === "application/pdf"){
filesArray.push(file);
}
}
displayFiles();
});
// Show files
function displayFiles(){
fileList.innerHTML = "";
filesArray.forEach((file, index)=>{
let li = document.createElement("li");
li.innerHTML = `
${file.name}
<button class="remove" onclick="removeFile(${index})">X</button>
`;
fileList.appendChild(li);
});
}
// Remove file
function removeFile(index){
filesArray.splice(index, 1);
displayFiles();
}
// Merge PDFs
mergeBtn.addEventListener("click", async function(){
if(filesArray.length < 2){
statusText.innerText = "Select at least 2 PDFs ❗";
return;
}
statusText.innerText = "Merging PDFs... ⏳";
const mergedPdf = await PDFDocument.create();
for (let file of filesArray) {
const bytes = await file.arrayBuffer();
const pdf = await PDFDocument.load(bytes);
const pages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
pages.forEach(page => mergedPdf.addPage(page));
}
const mergedBytes = await mergedPdf.save();
// Download file
const blob = new Blob([mergedBytes], { type: "application/pdf" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "merged.pdf";
a.click();
statusText.innerText = "Download started ✅";
}); Related Projects
Day 36 : Password Strength Visual Meter
Displays password strength with visual indicators and feedback.
Concepts: Input validation, regex, dynamic UI updates.
Day 37 : Time Zone Converter
Converts time between different time zones instantly.
Concepts: Date & time handling, user input, dynamic updates.
Day 1 : Admin Dashboard UI
User signup and login system with validated credentials and a clean UI.
Concepts: DOM manipulation, form validation, LocalStorage.