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

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

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales