Files
bentopdf/src/pages/compare-pdfs.html
T
2026-09-04 16:26:08 +05:30

1333 lines
43 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Primary Meta Tags -->
<meta
name="title"
content="Compare PDFs Online Free - Compare PDFs Tool | BentoPDF"
/>
<meta
name="description"
content="Compare two PDFs side by side. Free, no uploads, no signup. Runs entirely in your browser."
/>
<meta name="keywords" content="compare pdfs, online pdf" />
<meta name="author" content="BentoPDF" />
<meta
name="robots"
content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"
/>
<!-- Canonical URL -->
<link rel="canonical" href="https://www.bentopdf.com/compare-pdfs" />
<!-- Open Graph / Facebook / LinkedIn -->
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.bentopdf.com/compare-pdfs" />
<meta
property="og:title"
content="Compare PDFs Online Free - Compare PDFs Tool | BentoPDF"
/>
<meta
property="og:description"
content="Compare two PDFs side by side. Free, no uploads, no signup. Runs entirely in your browser."
/>
<meta
property="og:image"
content="https://www.bentopdf.com/images/og-compare-pdfs.png"
/>
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:site_name" content="BentoPDF" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:url" content="https://www.bentopdf.com/compare-pdfs" />
<meta name="twitter:title" content="Compare PDFs Free" />
<meta
name="twitter:description"
content="Compare two PDFs side by side. Free, no uploads, no signup. Runs entirely in your browser."
/>
<meta
name="twitter:image"
content="https://www.bentopdf.com/images/twitter-compare-pdfs.png"
/>
<meta name="twitter:site" content="@BentoPDF" />
<!-- Mobile Web App -->
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Compare PDFs" />
<title>Compare PDFs - BentoPDF</title>
<link href="/src/css/styles.css" rel="stylesheet" />
<style>
.compare-viewer-wrapper.overlay-mode {
position: relative;
display: flex;
align-items: stretch;
background: #ffffff;
overflow: hidden;
min-height: 0;
padding: 1.5rem;
}
.compare-viewer-wrapper.overlay-mode #panel-1 {
flex: 1 1 auto;
width: 100%;
height: 100%;
min-height: 0;
overflow: auto;
scrollbar-width: none;
-ms-overflow-style: none;
}
.compare-viewer-wrapper.overlay-mode #panel-1::-webkit-scrollbar {
display: none;
}
.compare-viewer-wrapper.overlay-mode #panel-2 {
position: absolute;
inset: 1.5rem;
min-height: 0;
overflow: hidden;
pointer-events: none;
background: transparent;
}
.compare-viewer-wrapper.overlay-mode .compare-panel-label {
display: none;
}
.compare-viewer-wrapper.overlay-mode .compare-canvas-stage canvas {
position: static;
top: auto;
left: auto;
width: auto;
height: auto;
}
.compare-viewer-wrapper.overlay-mode
#panel-2
.compare-canvas-stage
canvas {
background: transparent;
}
.compare-viewer-wrapper.side-by-side-mode {
display: flex;
gap: 0;
padding: 0;
background: #ffffff;
}
.compare-workspace {
display: grid;
gap: 1rem;
grid-template-columns: minmax(0, 1fr) 20rem;
align-items: stretch;
min-height: clamp(32rem, 72vh, 56rem);
}
.compare-viewer-wrapper {
height: 100%;
min-height: 0;
}
.compare-viewer-wrapper.side-by-side-mode #panel-1,
.compare-viewer-wrapper.side-by-side-mode #panel-2 {
flex: 1;
overflow: auto;
min-height: 0;
height: 100%;
border: none;
border-radius: 0;
box-shadow: none;
}
.compare-viewer-wrapper.side-by-side-mode #panel-1 {
border-right: 2px solid #cbd5e1;
}
.compare-panel {
position: relative;
min-width: 0;
min-height: 0;
background: #ffffff;
}
.compare-panel-label {
position: sticky;
top: 0;
z-index: 5;
padding: 0.5rem 1rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #64748b;
background: rgba(255, 255, 255, 0.95);
border-bottom: 1px solid #e2e8f0;
backdrop-filter: blur(4px);
}
.compare-canvas-stage {
--compare-stage-pad-top: 1.5rem;
--compare-stage-pad-x: 1.75rem;
--compare-stage-pad-bottom: 1.75rem;
position: relative;
width: max-content;
margin: 0 auto;
padding: var(--compare-stage-pad-top) var(--compare-stage-pad-x)
var(--compare-stage-pad-bottom);
}
.compare-canvas-stage canvas {
display: block;
background: #ffffff;
}
.compare-highlight-layer {
position: absolute;
inset: var(--compare-stage-pad-top) var(--compare-stage-pad-x)
var(--compare-stage-pad-bottom);
pointer-events: none;
}
.compare-highlight {
position: absolute;
border-radius: 2px;
border: none;
}
.compare-highlight.added {
background: rgba(34, 197, 94, 0.28);
}
.compare-highlight.removed,
.compare-highlight.page-removed {
background: rgba(239, 68, 68, 0.28);
}
.compare-highlight.modified {
background: rgba(245, 158, 11, 0.28);
}
.compare-highlight.moved {
background: rgba(168, 85, 247, 0.28);
}
.compare-highlight.style-changed {
background: rgba(59, 130, 246, 0.28);
}
.compare-highlight.active {
outline: 2px solid rgba(99, 102, 241, 0.7);
outline-offset: 1px;
}
.compare-placeholder {
position: absolute;
inset: 2rem;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 1rem;
border: 1px dashed #94a3b8;
border-radius: 0.75rem;
color: #475569;
background: rgba(255, 255, 255, 0.92);
}
.compare-placeholder.hidden {
display: none;
}
.compare-sidebar {
display: flex;
flex-direction: column;
gap: 0;
background: rgba(15, 23, 42, 0.6);
border: 1px solid rgba(51, 65, 85, 0.5);
border-radius: 0.75rem;
overflow: hidden;
height: 100%;
min-height: 0;
}
.compare-sidebar-header {
padding: 0.5rem 0.75rem;
border-bottom: 1px solid rgba(51, 65, 85, 0.5);
}
.compare-sidebar-filters {
display: flex;
flex-direction: column;
gap: 0;
padding: 0;
border-bottom: 1px solid rgba(51, 65, 85, 0.4);
}
.compare-filter-group {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.25rem;
padding: 0.375rem 0.75rem;
}
.compare-filter-group + .compare-filter-group {
border-top: 1px solid rgba(51, 65, 85, 0.25);
}
.compare-filter-label {
width: 100%;
font-size: 0.5625rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: #64748b;
}
.compare-pill {
display: inline-flex;
align-items: center;
gap: 0.1875rem;
border-radius: 9999px;
padding: 0.125rem 0.5rem;
font-size: 0.625rem;
font-weight: 600;
border: 1px solid transparent;
cursor: pointer;
transition: all 0.15s;
white-space: nowrap;
}
.compare-pill.removed {
color: #fca5a5;
background: rgba(239, 68, 68, 0.1);
border-color: rgba(239, 68, 68, 0.15);
}
.compare-pill.removed.active {
background: rgba(239, 68, 68, 0.25);
border-color: rgba(239, 68, 68, 0.5);
}
.compare-pill.modified {
color: #fcd34d;
background: rgba(245, 158, 11, 0.1);
border-color: rgba(245, 158, 11, 0.15);
}
.compare-pill.modified.active {
background: rgba(245, 158, 11, 0.25);
border-color: rgba(245, 158, 11, 0.5);
}
.compare-pill.added {
color: #86efac;
background: rgba(34, 197, 94, 0.1);
border-color: rgba(34, 197, 94, 0.15);
}
.compare-pill.added.active {
background: rgba(34, 197, 94, 0.25);
border-color: rgba(34, 197, 94, 0.5);
}
.compare-pill.moved {
color: #c4b5fd;
background: rgba(168, 85, 247, 0.1);
border-color: rgba(168, 85, 247, 0.15);
}
.compare-pill.moved.active {
background: rgba(168, 85, 247, 0.25);
border-color: rgba(168, 85, 247, 0.5);
}
.compare-pill.style-changed {
color: #93c5fd;
background: rgba(59, 130, 246, 0.1);
border-color: rgba(59, 130, 246, 0.15);
}
.compare-pill.style-changed.active {
background: rgba(59, 130, 246, 0.25);
border-color: rgba(59, 130, 246, 0.5);
}
.compare-pill.category {
color: #a5b4fc;
background: rgba(99, 102, 241, 0.1);
border-color: rgba(99, 102, 241, 0.15);
}
.compare-pill.category.active {
background: rgba(99, 102, 241, 0.25);
border-color: rgba(99, 102, 241, 0.5);
}
.compare-pill.category.disabled {
opacity: 0.35;
text-decoration: line-through;
}
.compare-change-list {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 0.75rem;
}
#compare-change-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.compare-change-item {
padding: 0.5rem 0.75rem;
cursor: pointer;
transition: background 0.15s;
border: 1px solid rgba(51, 65, 85, 0.3);
border-radius: 0.5rem;
font-size: 0.8125rem;
color: #cbd5e1;
line-height: 1.5;
}
.compare-change-item:hover {
background: rgba(99, 102, 241, 0.06);
border-color: rgba(99, 102, 241, 0.2);
}
.compare-change-item.active {
background: rgba(99, 102, 241, 0.1);
border-color: rgba(99, 102, 241, 0.3);
}
.compare-section-header {
display: flex;
align-items: center;
gap: 0.375rem;
padding: 0.25rem 0;
margin-top: 0.25rem;
}
.compare-section-label {
font-size: 0.6875rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.compare-section-label.added,
.compare-section-label.page-added {
color: #86efac;
}
.compare-section-label.removed,
.compare-section-label.page-removed {
color: #fca5a5;
}
.compare-section-label.modified {
color: #fcd34d;
}
.compare-section-label.moved {
color: #c4b5fd;
}
.compare-section-label.style-changed {
color: #93c5fd;
}
.compare-section-count {
font-size: 0.625rem;
font-weight: 600;
color: #64748b;
}
.compare-section-line {
flex: 1;
height: 1px;
background: rgba(51, 65, 85, 0.4);
}
.compare-change-dot {
width: 0.375rem;
height: 0.375rem;
border-radius: 50%;
flex-shrink: 0;
}
.compare-change-dot.added {
background: #22c55e;
}
.compare-change-dot.removed {
background: #ef4444;
}
.compare-change-dot.modified {
background: #f59e0b;
}
.compare-change-dot.page-added {
background: #22c55e;
}
.compare-change-dot.page-removed {
background: #ef4444;
}
.compare-change-dot.moved {
background: #a855f7;
}
.compare-change-dot.style-changed {
background: #3b82f6;
}
.compare-change-desc {
font-size: 0.8125rem;
color: #e2e8f0;
overflow-wrap: anywhere;
white-space: pre-line;
}
.compare-change-empty {
padding: 2rem 1rem;
font-size: 0.8125rem;
color: #64748b;
text-align: center;
}
@media (max-width: 1023px) {
.compare-workspace {
grid-template-columns: minmax(0, 1fr);
min-height: 0;
}
.compare-sidebar {
height: auto;
max-height: 24rem;
}
.compare-viewer-wrapper {
height: auto;
min-height: 24rem;
}
.compare-viewer-wrapper.side-by-side-mode {
gap: 1rem;
padding: 1rem;
}
.compare-canvas-stage {
--compare-stage-pad-top: 1rem;
--compare-stage-pad-x: 1rem;
--compare-stage-pad-bottom: 1rem;
}
}
</style>
<!-- Web App Manifest -->
<link rel="manifest" href="/site.webmanifest" />
<!-- Favicons -->
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg" />
<link
rel="icon"
type="image/png"
sizes="192x192"
href="/images/favicon-192x192.png"
/>
<link
rel="icon"
type="image/png"
sizes="512x512"
href="/images/favicon-512x512.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/images/apple-touch-icon.png"
/>
<link rel="icon" href="/favicon.ico" sizes="32x32" />
</head>
<body class="antialiased bg-gray-900">
{{> navbar }}
<div
id="uploader"
class="min-h-screen flex flex-col items-center justify-start py-12 p-4 bg-gray-900"
>
<div
id="tool-uploader"
class="bg-gray-800 rounded-xl shadow-xl px-4 py-8 md:p-8 max-w-[96rem] w-full text-gray-200 border border-gray-700"
>
<button
id="back-to-tools"
class="flex items-center gap-2 text-indigo-300 hover:text-indigo-400 mb-6 font-semibold"
>
<i data-lucide="arrow-left" class="cursor-pointer"></i>
<span class="cursor-pointer" data-i18n="tools.backToTools">
Back to Tools
</span>
</button>
<h1
class="text-2xl font-bold text-white mb-2"
data-i18n="tools:comparePdfs.name"
>
Compare PDFs
</h1>
<p class="text-gray-400 mb-6" data-i18n="tools:comparePdfs.subtitle">
Compare two PDFs side by side.
</p>
<!-- File Upload Areas -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div
id="drop-zone-1"
class="relative flex flex-col items-center justify-center w-full h-48 md:h-64 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-900 hover:bg-gray-700 transition-colors duration-300"
>
<div
id="file-display-1"
class="flex flex-col items-center justify-center"
>
<i data-lucide="file-text" class="w-8 h-8 mb-2 text-gray-400"></i>
<p
class="text-sm text-gray-400"
data-i18n="tools:comparePdfs.firstPdf"
>
First PDF
</p>
<p
class="text-xs text-gray-500"
data-i18n="tools:comparePdfs.clickOrDrop"
>
Click or drop
</p>
</div>
<input
id="file-input-1"
type="file"
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
accept="application/pdf"
/>
</div>
<div
id="drop-zone-2"
class="relative flex flex-col items-center justify-center w-full h-48 md:h-64 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-900 hover:bg-gray-700 transition-colors duration-300"
>
<div
id="file-display-2"
class="flex flex-col items-center justify-center"
>
<i data-lucide="file-text" class="w-8 h-8 mb-2 text-gray-400"></i>
<p
class="text-sm text-gray-400"
data-i18n="tools:comparePdfs.secondPdf"
>
Second PDF
</p>
<p
class="text-xs text-gray-500"
data-i18n="tools:comparePdfs.clickOrDrop"
>
Click or drop
</p>
</div>
<input
id="file-input-2"
type="file"
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
accept="application/pdf"
/>
</div>
</div>
<!-- Compare Viewer (hidden until both files loaded) -->
<div id="compare-viewer" class="hidden">
<!-- Toolbar -->
<div
class="flex flex-wrap items-center gap-3 mb-3 p-2 bg-gray-900 rounded-lg border border-gray-700"
>
<button
id="prev-page-compare"
class="btn p-1.5 rounded bg-gray-700 hover:bg-gray-600 disabled:opacity-50"
disabled
title="Previous page"
>
<i data-lucide="chevron-left" class="w-4 h-4"></i>
</button>
<span class="text-sm text-white font-medium">
Page <span id="current-page-display-compare">1</span> /
<span id="total-pages-display-compare">1</span>
</span>
<button
id="next-page-compare"
class="btn p-1.5 rounded bg-gray-700 hover:bg-gray-600 disabled:opacity-50"
disabled
title="Next page"
>
<i data-lucide="chevron-right" class="w-4 h-4"></i>
</button>
<div class="border-l border-gray-700 h-5 mx-1"></div>
<div class="bg-gray-700 p-0.5 rounded flex gap-0.5">
<button
id="view-mode-overlay"
class="btn bg-indigo-600 px-2.5 py-1 rounded text-xs font-semibold"
>
Overlay
</button>
<button
id="view-mode-side"
class="btn px-2.5 py-1 rounded text-xs font-semibold"
>
Side-by-Side
</button>
</div>
<div class="border-l border-gray-700 h-5 mx-1"></div>
<button
id="prev-change-btn"
class="btn bg-gray-700 hover:bg-gray-600 px-2.5 py-1 rounded text-xs font-semibold disabled:opacity-50"
disabled
title="Previous change"
>
<i data-lucide="chevron-up" class="w-3.5 h-3.5"></i>
</button>
<button
id="next-change-btn"
class="btn bg-gray-700 hover:bg-gray-600 px-2.5 py-1 rounded text-xs font-semibold disabled:opacity-50"
disabled
title="Next change"
>
<i data-lucide="chevron-down" class="w-3.5 h-3.5"></i>
</button>
<div class="border-l border-gray-700 h-5 mx-1"></div>
<button
id="zoom-out-btn"
class="btn p-1.5 rounded bg-gray-700 hover:bg-gray-600 disabled:opacity-50"
title="Zoom out"
>
<i data-lucide="minus" class="w-3.5 h-3.5"></i>
</button>
<span
id="zoom-level-display"
class="text-xs text-gray-300 font-medium min-w-[3rem] text-center select-none"
>100%</span
>
<button
id="zoom-in-btn"
class="btn p-1.5 rounded bg-gray-700 hover:bg-gray-600 disabled:opacity-50"
title="Zoom in"
>
<i data-lucide="plus" class="w-3.5 h-3.5"></i>
</button>
<button
id="zoom-reset-btn"
class="btn px-2.5 py-1 rounded bg-gray-700 hover:bg-gray-600 text-xs font-semibold"
title="Reset zoom to fit"
>
Fit
</button>
<div class="flex-1"></div>
<div id="overlay-controls" class="hidden flex items-center gap-2">
<div class="bg-gray-700 p-0.5 rounded flex gap-0.5">
<button
id="overlay-scope-all"
class="btn bg-indigo-600 px-2.5 py-1 rounded text-xs font-semibold"
>
All changes
</button>
<button
id="overlay-scope-content-only"
class="btn px-2.5 py-1 rounded text-xs font-semibold bg-gray-700"
>
Content only
</button>
</div>
<button
id="flicker-btn"
class="btn bg-gray-700 hover:bg-gray-600 px-2.5 py-1 rounded text-xs font-semibold"
>
Flicker
</button>
<label
class="flex items-center gap-1.5 text-xs text-gray-300 cursor-pointer"
>
<input
type="checkbox"
id="overlay-ocr-toggle"
checked
class="w-3.5 h-3.5 rounded text-indigo-600 bg-gray-700 border-gray-600"
/>
OCR
</label>
<input
type="range"
id="opacity-slider"
min="0"
max="1"
step="0.05"
value="0.5"
class="w-20 accent-indigo-500"
/>
</div>
<div id="side-by-side-controls" class="flex items-center gap-2">
<label
class="flex items-center gap-1.5 text-xs text-gray-300 cursor-pointer"
>
<input
type="checkbox"
id="sync-scroll-toggle"
checked
class="w-3.5 h-3.5 rounded text-indigo-600 bg-gray-700 border-gray-600"
/>
Sync scroll
</label>
<label
class="flex items-center gap-1.5 text-xs text-gray-300 cursor-pointer"
>
<input
type="checkbox"
id="ocr-toggle"
checked
class="w-3.5 h-3.5 rounded text-indigo-600 bg-gray-700 border-gray-600"
/>
OCR
</label>
</div>
<div class="relative" id="export-dropdown-wrapper">
<button
id="export-dropdown-btn"
class="btn bg-indigo-600 hover:bg-indigo-500 px-3 py-1.5 rounded text-xs font-semibold flex items-center gap-1.5 disabled:opacity-50"
disabled
>
<i data-lucide="upload" class="w-3.5 h-3.5"></i>
Export
<i data-lucide="chevron-down" class="w-3 h-3"></i>
</button>
<div
id="export-dropdown-menu"
class="hidden absolute right-0 top-full mt-1 w-48 bg-gray-800 border border-gray-600 rounded-lg shadow-xl z-50 py-1"
>
<div
class="px-3 py-1.5 text-[10px] font-semibold text-gray-400 uppercase tracking-wider"
>
Export as PDF
</div>
<button
data-export-mode="overlay"
class="export-menu-item export-menu-item-overlay w-full px-3 py-2 text-sm text-left text-gray-200 hover:bg-gray-700 flex items-center gap-2 hidden"
>
<i data-lucide="layers" class="w-4 h-4 text-gray-400"></i>
Overlay view
</button>
<button
data-export-mode="split"
class="export-menu-item export-menu-item-side w-full px-3 py-2 text-sm text-left text-gray-200 hover:bg-gray-700 flex items-center gap-2"
>
<i data-lucide="columns-2" class="w-4 h-4 text-gray-400"></i>
Split view
</button>
<button
data-export-mode="alternating"
class="export-menu-item export-menu-item-side w-full px-3 py-2 text-sm text-left text-gray-200 hover:bg-gray-700 flex items-center gap-2"
>
<i data-lucide="layers" class="w-4 h-4 text-gray-400"></i>
Alternating
</button>
<button
data-export-mode="left"
class="export-menu-item export-menu-item-side w-full px-3 py-2 text-sm text-left text-gray-200 hover:bg-gray-700 flex items-center gap-2"
>
<i data-lucide="columns-2" class="w-4 h-4 text-gray-400"></i>
Left Document
</button>
<button
data-export-mode="right"
class="export-menu-item export-menu-item-side w-full px-3 py-2 text-sm text-left text-gray-200 hover:bg-gray-700 flex items-center gap-2"
>
<i data-lucide="columns-2" class="w-4 h-4 text-gray-400"></i>
Right Document
</button>
</div>
</div>
</div>
<div class="compare-workspace">
<div
id="compare-viewer-wrapper"
class="compare-viewer-wrapper side-by-side-mode border border-slate-200 relative"
>
<div id="panel-1" class="compare-panel overflow-auto">
<div class="compare-panel-label" id="compare-panel-label-1">
Original
</div>
<div class="compare-canvas-stage">
<canvas id="canvas-compare-1" class="block mx-auto"></canvas>
<div id="highlights-1" class="compare-highlight-layer"></div>
<div
id="placeholder-1"
class="compare-placeholder hidden"
></div>
</div>
</div>
<div id="panel-2" class="compare-panel overflow-auto">
<div class="compare-panel-label" id="compare-panel-label-2">
Modified
</div>
<div class="compare-canvas-stage">
<canvas
id="canvas-compare-2"
class="block mx-auto"
style="opacity: 1"
></canvas>
<div id="highlights-2" class="compare-highlight-layer"></div>
<div
id="placeholder-2"
class="compare-placeholder hidden"
></div>
</div>
</div>
</div>
<aside class="compare-sidebar">
<div class="compare-sidebar-header">
<div class="relative">
<span
class="absolute inset-y-0 left-0 flex items-center pl-3"
>
<i data-lucide="search" class="w-4 h-4 text-gray-400"></i>
</span>
<input
type="text"
id="compare-search-input"
placeholder="Search changes..."
class="w-full pl-9 pr-3 py-2 bg-gray-700 text-white text-sm border border-gray-600 rounded-lg focus:ring-indigo-500 focus:border-indigo-500"
/>
</div>
</div>
<div class="compare-sidebar-filters">
<div class="compare-filter-group">
<div class="compare-filter-label">Change Type</div>
<button id="filter-removed" class="compare-pill removed">
<span class="compare-change-dot removed"></span>
<span id="summary-removed-count">0</span> Deleted
</button>
<button id="filter-added" class="compare-pill added">
<span class="compare-change-dot added"></span>
<span id="summary-added-count">0</span> Added
</button>
<button id="filter-modified" class="compare-pill modified">
<span class="compare-change-dot modified"></span>
<span id="summary-modified-count">0</span> Modified
</button>
<button id="filter-moved" class="compare-pill moved">
<span class="compare-change-dot moved"></span>
<span id="summary-moved-count">0</span> Moved
</button>
<button
id="filter-style-changed"
class="compare-pill style-changed"
>
<span class="compare-change-dot style-changed"></span>
<span id="summary-style-changed-count">0</span> Style
</button>
</div>
<div class="compare-filter-group">
<div class="compare-filter-label">Content</div>
<button
id="category-text"
class="compare-pill category active"
>
<span id="category-count-text">0</span> Text
</button>
<button
id="category-image"
class="compare-pill category active"
>
<span id="category-count-image">0</span> Images
</button>
<button
id="category-header-footer"
class="compare-pill category active"
>
<span id="category-count-header-footer">0</span> Headers
</button>
<button
id="category-annotation"
class="compare-pill category active"
>
<span id="category-count-annotation">0</span> Annotations
</button>
<button
id="category-formatting"
class="compare-pill category active"
>
<span id="category-count-formatting">0</span> Formatting
</button>
<button
id="category-background"
class="compare-pill category active"
>
<span id="category-count-background">0</span> Backgrounds
</button>
</div>
</div>
<div class="compare-change-list">
<div id="change-list-empty" class="compare-change-empty">
Upload two PDFs to see differences.
</div>
<div id="compare-change-list" class="hidden"></div>
</div>
</aside>
</div>
</div>
</div>
</div>
<!-- Loader Modal -->
<div
id="loader-modal"
class="hidden fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50"
>
<div
class="bg-gray-800 p-8 rounded-lg flex flex-col items-center gap-4 border border-gray-700 shadow-xl"
>
<div class="solid-spinner"></div>
<p
id="loader-text"
class="text-white text-lg font-medium"
data-i18n="loader.processing"
data-i18n="loader.processing"
>
Processing...
</p>
</div>
</div>
<!-- Alert Modal -->
<div
id="alert-modal"
class="fixed inset-0 bg-gray-900 bg-opacity-90 flex items-center justify-center z-50 hidden"
>
<div
class="bg-gray-800 rounded-lg shadow-xl p-6 max-w-sm w-full border border-gray-700"
>
<h3
id="alert-title"
class="text-xl font-bold text-white mb-2"
data-i18n="alert.title"
data-i18n="alert.title"
>
Alert
</h3>
<p id="alert-message" class="text-gray-300 mb-6"></p>
<button
id="alert-ok"
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-4 rounded-lg transition-colors duration-200"
>
OK
</button>
</div>
</div>
<!-- How It Works Section -->
<section class="max-w-4xl mx-auto px-4 py-12">
<h2
class="text-2xl md:text-3xl font-bold text-white mb-8 text-center"
data-i18n="howItWorks.title"
>
How It Works
</h2>
<div class="space-y-6">
<div class="flex items-start gap-4">
<div
class="flex-shrink-0 w-10 h-10 bg-indigo-600 rounded-full flex items-center justify-center text-white font-bold"
>
1
</div>
<div class="flex-1">
<h3 class="text-lg font-semibold text-white mb-1">Upload File</h3>
<p class="text-gray-400" data-i18n="howItWorks.step1">
Click or drag and drop your file to begin
</p>
</div>
</div>
<div class="flex items-start gap-4">
<div
class="flex-shrink-0 w-10 h-10 bg-indigo-600 rounded-full flex items-center justify-center text-white font-bold"
>
2
</div>
<div class="flex-1">
<h3 class="text-lg font-semibold text-white mb-1">Process</h3>
<p class="text-gray-400" data-i18n="howItWorks.step2">
Click the process button to start
</p>
</div>
</div>
<div class="flex items-start gap-4">
<div
class="flex-shrink-0 w-10 h-10 bg-indigo-600 rounded-full flex items-center justify-center text-white font-bold"
>
3
</div>
<div class="flex-1">
<h3 class="text-lg font-semibold text-white mb-1">Download</h3>
<p class="text-gray-400" data-i18n="howItWorks.step3">
Save your processed file instantly
</p>
</div>
</div>
</div>
</section>
<!-- Related Tools Section -->
<section class="max-w-6xl mx-auto px-4 py-12">
<h2
class="text-2xl md:text-3xl font-bold text-white mb-6 text-center"
data-i18n="relatedTools.title"
>
Related PDF Tools
</h2>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
<a
href="merge-pdf.html"
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
>
<h3 class="text-white font-semibold mb-1">Merge PDF</h3>
<p class="text-gray-400 text-sm">Free online merge PDF tool</p>
</a>
<a
href="compress-pdf.html"
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
>
<h3 class="text-white font-semibold mb-1">Compress PDF</h3>
<p class="text-gray-400 text-sm">Free online compress PDF tool</p>
</a>
<a
href="split-pdf.html"
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
>
<h3 class="text-white font-semibold mb-1">Split PDF</h3>
<p class="text-gray-400 text-sm">Free online split PDF tool</p>
</a>
<a
href="edit-pdf.html"
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
>
<h3 class="text-white font-semibold mb-1">Edit PDF</h3>
<p class="text-gray-400 text-sm">Free online edit PDF tool</p>
</a>
<a
href="rotate-pdf.html"
class="block bg-gray-800 p-4 rounded-lg hover:bg-gray-700 transition-colors border border-gray-700"
>
<h3 class="text-white font-semibold mb-1">Rotate PDF</h3>
<p class="text-gray-400 text-sm">Free online rotate PDF tool</p>
</a>
</div>
</section>
<!-- FAQ Section -->
<section class="max-w-4xl mx-auto px-4 py-12">
<h2
class="text-2xl md:text-3xl font-bold text-white mb-6 text-center"
data-i18n="faq.sectionTitle"
>
Frequently Asked Questions
</h2>
<div class="faq-list">
<details class="faq-d">
<summary class="faq-d-q">
How do I see what changed between two versions of a PDF?
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
Upload the original as the first PDF and the revised version as the
second. The tool pairs matching pages, then highlights added,
deleted, modified, and moved content on each page pair, with
counters showing how many changes of each kind were found.
</p>
</details>
<details class="faq-d">
<summary class="faq-d-q">
What is the difference between side-by-side and overlay mode?
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
Side-by-side shows the two pages next to each other with
synchronized scrolling, which is easiest for reading text changes.
Overlay stacks the revised page on top of the original with an
opacity slider, so shifted or resized elements stand out, and the
Flicker button switches the top page on and off to make small moves
visible.
</p>
</details>
<details class="faq-d">
<summary class="faq-d-q">
Can it compare scanned PDFs that have no text layer?
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
With OCR turned on, page images are run through Tesseract in your
browser and the recognized text is compared, so scanned documents
can be checked. OCR currently uses the English language model, and
it's slower than comparing PDFs that already contain text.
</p>
</details>
<details class="faq-d">
<summary class="faq-d-q">
Can I filter out formatting changes and only see text differences?
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
Changes are grouped into text, image, header/footer, annotation,
formatting, and background categories, each with its own toggle.
Turn off the categories you don't care about, and use the text
search box to find a specific changed word or phrase.
</p>
</details>
<details class="faq-d">
<summary class="faq-d-q">
What happens when pages were added, removed, or reordered between
versions?
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
Pages are paired by content similarity rather than by page number,
so an inserted page doesn't throw off everything after it. A page
with no counterpart is reported as added or removed, and the page
navigation steps through the pairs the tool built.
</p>
</details>
<details class="faq-d">
<summary class="faq-d-q">
Does it detect changes to comments and annotations?
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
Annotation changes are their own category, so added or removed
comments, highlights, and markup are flagged separately from body
text and can be shown or hidden with the annotation filter.
</p>
</details>
<details class="faq-d">
<summary class="faq-d-q">
Can I save the comparison as a report?
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
The Export as PDF menu produces a PDF of the comparison. In
side-by-side mode you can choose a split view, alternating pages, or
only the left or right document with highlights; in overlay mode it
exports the overlay view.
</p>
</details>
<details class="faq-d">
<summary class="faq-d-q">
Are the two PDFs sent anywhere to be compared?
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
No. Rendering, page pairing, OCR, and change detection all run in
your browser with WebAssembly and web workers, and nothing is
transmitted, so contracts and other confidential drafts stay on your
machine.
</p>
</details>
</div>
</section>
{{> footer }}
<script type="module" src="/src/js/utils/lucide-init.ts"></script>
<script type="module" src="/src/js/utils/full-width.ts"></script>
<script type="module" src="/src/js/utils/simple-mode-footer.ts"></script>
<script type="module" src="/src/js/logic/compare-pdfs-page.ts"></script>
<script type="module" src="/src/js/mobileMenu.ts"></script>
<script type="module" src="/src/js/main.ts"></script>
<!-- JSON-LD Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Compare PDFs - BentoPDF",
"applicationCategory": "PDF Tool",
"operatingSystem": "Any - Web Browser",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "How to compare pdfs online",
"description": "Learn how to compare pdfs using BentoPDF",
"step": [
{
"@type": "HowToStep",
"position": 1,
"name": "Upload File",
"text": "Click or drag and drop your file"
},
{
"@type": "HowToStep",
"position": 2,
"name": "Process",
"text": "Click the process button"
},
{
"@type": "HowToStep",
"position": 3,
"name": "Download",
"text": "Download your processed file"
}
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://www.bentopdf.com"
},
{
"@type": "ListItem",
"position": 2,
"name": "Compare PDFs",
"item": "https://www.bentopdf.com/compare-pdfs"
}
]
}
</script>
</body>
</html>