Side-by-Side Showcase Demo Code Sample

Requirements
View Demo

Quickly view and compare PDFs, Office documents, and images with a side-by-side layout. Keep both documents in sync as you scroll and zoom for a seamless comparison experience.

This demo allows you to:

  • Upload and choose your own documents.
  • View two files side-by-side.
  • Toggle synchronized scrolling and zooming between documents.

Implementation steps

To add Side-by-Side viewing capability with WebViewer:
Step 1: Get started with WebViewer in your preferred web stack.
Step 2: Add the ES6 JavaScript sample code provided in this guide.

Once you generate your license key, it will automatically be included in your sample code below.

License Key

1// ES6 Compliant Syntax
2// GitHub Copilot, Claude Sonnet 4 (Preview), October 16, 2025
3// File: showcase-demos/side-by-side/index.js
4import WebViewer from '@pdftron/webviewer';
5
6const licenseKey = 'YOUR_WEBVIEWER_LICENSE_KEY';
7
8// Global variables to track state
9const defaultDoc1 = 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/demo-annotated.pdf';
10const defaultDoc2 = 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf';
11let syncScroll = false;
12let isUpdatingSync = false; // Guard flag to prevent circular calls
13let file1 = null;
14let file2 = null;
15let title1 = '';
16let title2 = '';
17let canStartComparing = false;
18
19// Store references for cleanup
20let documentViewer1 = null;
21let documentViewer2 = null;
22let multiViewerReadyHandler = null;
23let documentLoadedHandler1 = null;
24let documentLoadedHandler2 = null;
25
26// Function to initialize and load the Redaction Tool
27function initializeWebViewer() {
28
29 const element = document.getElementById('viewer');
30 if (!element) {
31 console.error('Viewer div not found.');
32 return;
33 }
34
35 WebViewer({
36 path: '/lib',
37 licenseKey: licenseKey,
38 }, element).then(instance => {
39 // Get Core and UI from the instance
40 const { Core, UI } = instance;
41
42 createUIElements();
43 UI.enableElements(['contentEditButton']);
44 UI.disableElements(['comparisonToggleButton']);
45 UI.enableFeatures([UI.Feature.MultiViewerMode]);
46 UI.enterMultiViewerMode();
47 // Create the multi-viewer ready handler
48 multiViewerReadyHandler = () => {
49 // Now both document viewers are available
50 documentViewer1 = Core.getDocumentViewers()[0];
51 documentViewer2 = Core.getDocumentViewers()[1];
52
53 // Create document loaded handlers
54 documentLoadedHandler1 = () => {
55 file1 = documentViewer1.getDocument();
56 };
57
58 documentLoadedHandler2 = () => {
59 file2 = documentViewer2.getDocument();
60 };
61
62 // Add document loaded event listeners
63 documentViewer1.addEventListener('documentLoaded', documentLoadedHandler1);
64 documentViewer2.addEventListener('documentLoaded', documentLoadedHandler2);
65
66 // Load default documents into both viewers
67 documentViewer1?.loadDocument(defaultDoc1);
68 documentViewer2?.loadDocument(defaultDoc2);
69
70 // Add event listeners to sync scroll & zoom button in both viewers
71 addSyncListener(documentViewer1, UI, syncScroll);
72 addSyncListener(documentViewer2, UI, syncScroll);
73 };
74
75 // Set up multi-viewer ready event
76 UI.addEventListener(UI.Events.MULTI_VIEWER_READY, multiViewerReadyHandler);
77
78 }).catch(error => {
79 console.error('Error initializing WebViewer:', error);
80 });
81}
82
83// Add event listener to sync scroll & zoom button in multi-viewer mode
84function addSyncListener(
85 documentViewer,
86 UI,
87 syncScroll
88) {
89 documentViewer
90 ?.getViewerElement()
91 ?.closest('.CompareContainer')
92 // The first button is the "Start Sync" button
93 ?.querySelector('.control-buttons button')
94 ?.addEventListener('click', () => {
95 setTimeout(() => {
96 syncScroll = UI.isMultiViewerSyncing();
97 setSyncScroll(syncScroll);
98 isUpdatingSync = true;
99 UIElements.updateSyncToggleUIOnly(syncScroll);
100 }, 0);
101 });
102};
103
104// Function to sync up document viewers to scroll and zoom together
105function setSyncScroll(value) {
106 syncScroll = value;
107 toggleSyncScrollZoom(syncScroll);
108}
109
110// Function to enable/disable sync scroll & zoom
111function toggleSyncScrollZoom(enable) {
112 if (enable) {
113 window.WebViewer.getInstance().UI.enableMultiViewerSync();
114 console.log('Sync scroll & zoom enabled');
115 syncScroll = true;
116 } else {
117 window.WebViewer.getInstance().UI.disableMultiViewerSync();
118 console.log('Sync scroll & zoom disabled');
119 syncScroll = false;
120 }
121}
122
123// Expose file variables and functions to the global scope for UI interaction
124window.toggleSyncScrollZoom = toggleSyncScrollZoom;
125window.isUpdatingSync = isUpdatingSync;
126window.file1 = file1;
127window.file2 = file2;
128window.title1 = title1;
129window.title2 = title2;
130window.canStartComparing = canStartComparing;
131
132// UI Elements
133// Function to create and initialize UI elements
134function createUIElements() {
135 // Create a container for all controls (label, dropdown, and buttons)
136 // Dynamically load ui-elements.js if not already loaded
137 if (!window.SidePanel) {
138 const script = document.createElement('script');
139 script.src = '/showcase-demos/side-by-side/ui-elements.js';
140 script.onload = () => {
141 UIElements.init('viewer');
142 };
143 document.head.appendChild(script);
144 }
145}
146
147// Initialize the WebViewer
148initializeWebViewer();
149

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales