Easily customize UI elements in the viewer's toolbar, buttons, and menus. Change their colors or use your own icons.
This demo allows you to:
Implementation steps
To add Toolbar Customization capability with WebViewer:
Step 1: Choose 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.
Apryse collects some data regarding your usage of the SDK for product improvement.
The data that Apryse collects include:
For clarity, no other data is collected by the SDK and Apryse has no access to the contents of your documents.
If you wish to continue without data collection, contact us and we will email you a no-tracking trial key for you to get started.
1// ES6 Compliant Syntax
2// Copilot name: GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-09-29
3// File: toolbar-customization/index.js
4
5import WebViewer from '@pdftron/webviewer';
6
7const licenseKey = 'YOUR_WEBVIEWER_LICENSE_KEY';
8
9
10function initializeWebViewer() {
11 WebViewer(
12 {
13 path: '/lib',
14 initialDoc: 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf',
15 enableFilePicker: true, // Enable file picker to open files. In WebViewer -> menu icon -> Open File
16 enableMeasurement: true,
17 licenseKey: licenseKey, // Replace with your license key
18 },
19 document.getElementById('viewer')
20 ).then((instance) => {
21
22 // Collect webViewer data
23 collectWebViewerData(instance);
24
25 // Customize the webviewer left panel after the load completion
26 instance.Core.documentViewer.addEventListener('documentLoaded', () => {
27 customizeUI();
28 });
29
30 console.log('WebViewer loaded successfully.');
31 }).catch((error) => {
32 console.error('Failed to initialize WebViewer:', error);
33 });
34}
35
36// UI elements section
37
38
39// Object to hold WebViewer related data
40const webViewerData = {
41 instance: null,
42 wcViewer: null,
43 windowDoc: null,
44 defaultBackgroundColor: '',
45};
46
47// Collect webViewer data
48const collectWebViewerData = (instance) => {
49 webViewerData.instance = instance;
50 webViewerData.wcViewer = document.getElementById('wc-viewer');
51 webViewerData.windowDoc = webViewerData.wcViewer?.shadowRoot;
52 let uiElement = webViewerData.windowDoc.querySelector(`[data-element='${UIElements.uiElementsMap[0].id}']`);
53 if (uiElement.style.backgroundColor !== null && uiElement.style.backgroundColor !== '')
54 webViewerData.defaultBackgroundColor = uiElement.style.backgroundColor;
55};
56
57// Customize the webviewer left panel
58const customizeUI = () => {
59 const { UI } = webViewerData.instance;
60
61 // Enable the customizable UI feature flag
62 UI.enableFeatureFlag(UI.FeatureFlags.CUSTOMIZABLE_UI);
63
64 // Enable all UI elements initially
65 UI.enableAllElements();
66
67 // Fit the page to the viewer width
68 UI.setFitMode(UI.FitMode.FitPage);
69
70 // Set the layout to single page mode
71 UI.setLayoutMode(UI.LayoutMode.Single);
72
73 // Keep the page navigation component on screen all the time
74 UI.disableFadePageNavigationComponent();
75
76 // Enable the annotation toolbar group
77 UI.enableElements(['toolbarGroup-Annotate']);
78
79 // Close the tab panel (if it's open) for refreshment.
80 UI.closeElements([UIElements.tabPanel.dataElement]);
81
82 // Get the list of registered panels in the webviewer
83 UIElements.viewerPanels = UI.getPanels();
84
85 // Find the Tab Panel to modify. The customize toolbar sub-panel will be added to this Tab panel.
86 UIElements.tabPanel.handle = UIElements.viewerPanels.find((panel) => panel.dataElement === UIElements.tabPanel.dataElement);
87
88 // Register the customize toolbar sub-panel
89 RegisterCustomizeToolbarPanel();
90
91 // Add the new customize toolbar sub-panel to list of sub-panels under the Tab Panel
92 UIElements.customizeToolbarPanel.handle = { render: UIElements.customizeToolbarPanel.dataElement };
93 UIElements.tabPanel.handle.panelsList = [UIElements.customizeToolbarPanel.handle, ...UIElements.tabPanel.handle.panelsList];
94
95 UI.openElements([UIElements.tabPanel.dataElement]);
96};
97
98// Register the customize toolbar sub-panel
99const RegisterCustomizeToolbarPanel = () => {
100 UIElements.customizeToolbarPanel.render = UIElements.createCustomizeToolbarPanelElements();
101 webViewerData.instance.UI.addPanel({
102 dataElement: UIElements.customizeToolbarPanel.dataElement,
103 location: 'left',
104 icon: '<svg fill="#000000" width="18px" height="18px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M30 2.994h-28c-1.099 0-2 0.9-2 2v17.006c0 1.099 0.9 1.999 2 1.999h13v3.006h-5c-0.552 0-1 0.448-1 1s0.448 1 1 1h12c0.552 0 1-0.448 1-1s-0.448-1-1-1h-5v-3.006h13c1.099 0 2-0.9 2-1.999v-17.006c0-1.1-0.901-2-2-2zM30 22h-28v-17.006h28v17.006z"></path></svg>',
105 title: 'Customize Toolbar',
106 render: () => UIElements.customizeToolbarPanel.render,
107 });
108};
109
110// Enable or disable a UI element visibility
111//Made global to be accessible in ui-elements.js
112window.toggleElementVisibility = (element) => {
113 (webViewerData.instance.UI.isElementDisabled(element.id)) ?
114 webViewerData.instance.UI.enableElements([element.id]) :
115 webViewerData.instance.UI.disableElements([element.id]);
116};
117
118// Handle mouse over event, either for a checkbox or label control:
119// - change cursor to pointer
120// - toggle the UI element highlight
121window.controlOnMouseOver = (control, element) => {
122 control.style.cursor = 'pointer';
123
124 // Open the menu overlay when mouse is over the download or print button checkbox/label
125 if (element.id === 'downloadButton' || element.id === 'printButton') {
126 if (webViewerData.instance.UI.isElementDisabled('menuOverlay'))
127 webViewerData.instance.UI.enableElements('menuOverlay');
128
129 if (!webViewerData.instance.UI.isElementOpen('menuOverlay'))
130 webViewerData.instance.UI.openElements('menuOverlay');
131 }
132
133 toggleElementHighlight(element);
134};
135
136// Handle mouse leave event, either for a checkbox or label control:
137// - change cursor to default
138// - toggle the UI element highlight
139window.controlOnMouseLeave = (control, element) => {
140 control.style.cursor = 'default';
141
142 // Close the menu overlay when mouse leaves the download or print button checkbox/label
143 if (element.id === 'downloadButton' || element.id === 'printButton') {
144 if (webViewerData.instance.UI.isElementDisabled('menuOverlay'))
145 webViewerData.instance.UI.enableElements('menuOverlay');
146
147 if (webViewerData.instance.UI.isElementOpen('menuOverlay'))
148 webViewerData.instance.UI.closeElements('menuOverlay');
149 }
150
151 toggleElementHighlight(element);
152};
153
154// Highlight or reset highlight of a UI element
155window.toggleElementHighlight = (element) => {
156 let uiElement = webViewerData.windowDoc.querySelector(`[data-element='${element.id}']`);
157 if (uiElement !== null) {
158 if (uiElement.style.backgroundColor === 'orange')
159 uiElement.style.backgroundColor = webViewerData.defaultBackgroundColor;
160 else
161 uiElement.style.backgroundColor = 'orange';
162 }
163};
164
165//helper function to load the ui-elements.js script
166function loadUIElementsScript() {
167 return new Promise((resolve, reject) => {
168 if (window.UIElements) {
169 console.log('UIElements already loaded');
170 resolve();
171 return;
172 }
173
174 const script = document.createElement('script');
175 script.src = '/showcase-demos/toolbar-customization/ui-elements.js';
176 script.onload = function () {
177 console.log('✅ UIElements script loaded successfully');
178 resolve();
179 };
180 script.onerror = function () {
181 console.error('Failed to load UIElements script');
182 reject(new Error('Failed to load ui-elements.js'));
183 };
184 document.head.appendChild(script);
185 });
186}
187
188// Load UIElements script first, then initialize WebViewer
189loadUIElementsScript().then(() => {
190 initializeWebViewer();
191}).catch((error) => {
192 console.error('Failed to load UIElements:', error);
193});
194
1// ES6 Compliant Syntax
2// Copilot name: GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-09-29
3// File: toolbar-customization/ui-elements.js
4
5// Class with static UI elements and related functions for the toolbar customization demo
6
7class UIElements {
8
9 // The list of registered panels in the webviewer
10 static viewerPanels = null;
11 // Convert a label to a valid ID by removing spaces
12 static labelToId = (label) => label.replace(/\s+/g, '');
13
14 // The tab panel, representing the webviewer left panel
15 static tabPanel = {
16 handle: null,
17 dataElement: 'tabPanel'
18 };
19
20 // The customize toolbar sub-panel to be registered
21 static customizeToolbarPanel = {
22 handle: null,
23 dataElement: 'customizeToolbarPanel',
24 render: null,
25 };
26
27 // The UI elements list to be used in showing / hiding controls in the webviewer
28 static uiElementsMap = [
29 {
30 label: 'Top Header',
31 id: 'default-top-header',
32 checked: true,
33 },
34 {
35 label: 'Tools Header',
36 id: 'tools-header',
37 checked: true,
38 },
39 {
40 label: 'Download PDF',
41 id: 'downloadButton',
42 checked: true,
43 },
44 {
45 label: 'Print PDF',
46 id: 'printButton',
47 checked: true,
48 },
49 {
50 label: 'Annotation Tools',
51 id: 'toolbarGroup-Annotate',
52 checked: true,
53 list: [
54 {
55 label: 'Highlight',
56 id: 'highlightToolButton',
57 checked: true,
58 },
59 {
60 label: 'Underline',
61 id: 'underlineToolButton',
62 checked: true,
63 },
64 {
65 label: 'Strikeout',
66 id: 'strikeoutToolButton',
67 checked: true,
68 },
69 {
70 label: 'Squiggly',
71 id: 'squigglyToolButton',
72 checked: true,
73 },
74 {
75 label: 'Free Hand',
76 id: 'freeHandToolButton',
77 checked: true,
78 },
79 {
80 label: 'Free Hand Highlight',
81 id: 'freeHandHighlightToolButton',
82 checked: true,
83 },
84 {
85 label: 'Free Text',
86 id: 'freeTextToolButton',
87 checked: true,
88 },
89 {
90 label: 'Insert Text',
91 id: 'markInsertTextToolButton',
92 checked: true,
93 },
94 {
95 label: 'Replace Text',
96 id: 'markReplaceTextToolButton',
97 checked: true,
98 },
99 {
100 label: 'Sticky',
101 id: 'stickyToolButton',
102 checked: true,
103 },
104 {
105 label: 'Callout',
106 id: 'calloutToolButton',
107 checked: true,
108 },
109 {
110 label: 'Eraser',
111 id: 'eraserToolButton',
112 checked: true,
113 },
114 ],
115 },
116 {
117 label: 'Overlays',
118 id: 'Overlays',
119 checked: true,
120 list: [
121 {
122 label: 'View Modes',
123 id: 'view-controls-toggle-button',
124 checked: true,
125 },
126 {
127 label: 'Left Panel',
128 id: 'leftPanelButton',
129 checked: true,
130 },
131 {
132 label: 'Search Panel',
133 id: 'searchPanelToggle',
134 checked: true,
135 },
136 {
137 label: 'Overflow Menu',
138 id: 'menuButton',
139 checked: true,
140 },
141 {
142 label: 'Page Number',
143 id: 'page-nav-floating-header',
144 checked: true,
145 },
146 ],
147 },
148 ];
149
150 // Create the customize toolbar panel elements.
151 static createCustomizeToolbarPanelElements = () => {
152 let panelDiv = document.createElement('div');
153 panelDiv.id = 'customizeToolbar';
154
155 let paragraph = document.createTextNode('A demo of the UI flexibility of WebViewer, a JavaScript-based PDF SDK for web apps. Easily hide buttons, change colors, or use your own icons via simple APIs.');
156 panelDiv.appendChild(paragraph);
157
158 let dividerDiv = document.createElement('div');
159 dividerDiv.style.borderTop = '1px solid #ccc';
160 dividerDiv.style.margin = '10px 0';
161 panelDiv.appendChild(dividerDiv);
162
163 // Hide / Show division
164 let hideShowDiv = document.createElement('div');
165 hideShowDiv.id = 'hideShow';
166
167 let hideShowTitle = document.createElement("h3");
168 hideShowTitle.textContent = "Hide / Show features in the UI";
169 hideShowDiv.appendChild(hideShowTitle);
170 hideShowDiv.appendChild(document.createElement('p'));
171 panelDiv.appendChild(hideShowDiv);
172
173 // Create checkboxes for items in the uiElementsMap array
174 this.uiElementsMap.forEach(element => {
175
176 this.createCheckbox(panelDiv, element);
177
178 let hasSubCheckboxes = (element.list && element.list.length > 0);
179 if (hasSubCheckboxes)
180 element.list.forEach(item => this.createCheckbox(panelDiv, item, hasSubCheckboxes));
181 });
182
183 panelDiv.appendChild(dividerDiv.cloneNode());
184
185 return panelDiv;
186 };
187
188 // Create a checkbox and its label, and add them to the customize toolbar panel
189 static createCheckbox = (panelDiv, element, isSubCheckbox = false) => {
190
191 // Checkbox input
192 let checkbox = document.createElement('input');
193 checkbox.type = 'checkbox';
194 checkbox.id = `${this.labelToId(element.label)}${checkbox.type}`;
195 checkbox.checked = element.checked;
196 checkbox.onmouseover = () => controlOnMouseOver(checkbox, element);
197 checkbox.onmouseleave = () => controlOnMouseLeave(checkbox, element);
198 checkbox.onclick = () => this.controlOnClick(element);
199 if (isSubCheckbox)
200 checkbox.style.marginLeft = '20px';
201
202 // Checkbox label
203 let label = document.createElement('label');
204 label.textContent = element.label;
205 label.onmouseover = () => controlOnMouseOver(label, element);
206 label.onmouseleave = () => controlOnMouseLeave(label, element);
207 label.onclick = () => {
208 checkbox.checked = !checkbox.checked;
209 this.controlOnClick(element);
210 };
211
212 panelDiv.appendChild(document.createElement('p'));
213 panelDiv.appendChild(checkbox);
214 panelDiv.appendChild(label);
215 };
216
217 // Handle click event, either for a checkbox or label control:
218 // - toggle the UI element visibility
219 // - toggle the UI element highlight
220 static controlOnClick = (element) => {
221
222 // If a UI element has sub-checkboxes, toggle them as well
223 if (element.list !== null && element.list !== undefined && element.list.length > 0) {
224 element.list.forEach(item => {
225 // Toggle the sub-checkbox UI element visibility
226 toggleElementVisibility(item);
227 const subCheckBox = this.checkBoxControl(item);
228 subCheckBox.checked = !subCheckBox.checked;
229 });
230 }
231 // Otherwise, just toggle the current UI element visibility
232 else
233 toggleElementVisibility(element);
234
235 // Toggle the UI element highlight
236 toggleElementHighlight(element);
237 };
238
239 // Get the checkbox control based on an item from the uiElementsMap array
240 static checkBoxControl = (item) => {
241 const checkbox = this.customizeToolbarPanel.render.querySelector(`#${this.labelToId(item.label)}checkbox`);
242 return checkbox;
243 };
244}
245
Did you find this helpful?
Trial setup questions?
Ask experts on DiscordNeed other help?
Contact SupportPricing or product questions?
Contact Sales