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
7
8function initializeWebViewer() {
9 WebViewer(
10 {
11 path: '/lib',
12 initialDoc: 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf',
13 enableFilePicker: true, // Enable file picker to open files in WebViewer -> menu icon -> Open File.
14 enableMeasurement: true,
15 licenseKey: 'YOUR_LICENSE_KEY', // Replace with your license key.
16 },
17 document.getElementById('viewer')
18 ).then((instance) => {
19
20 // Collect webViewer data.
21 collectWebViewerData(instance);
22
23 // Customize the webviewer left panel after the load completion.
24 instance.Core.documentViewer.addEventListener('documentLoaded', () => {
25 customizeUI();
26 });
27
28 console.log('WebViewer loaded successfully.');
29 }).catch((error) => {
30 console.error('Failed to initialize WebViewer:', error);
31 });
32}
33
34// UI elements section
35
36
37// Object to hold WebViewer related data.
38const webViewerData = {
39 instance: null,
40 wcViewer: null,
41 windowDoc: null,
42 defaultBackgroundColor: '',
43};
44
45// Collect webViewer data.
46const collectWebViewerData = (instance) => {
47 webViewerData.instance = instance;
48 webViewerData.wcViewer = document.getElementById('wc-viewer');
49 webViewerData.windowDoc = webViewerData.wcViewer?.shadowRoot;
50 let uiElement = webViewerData.windowDoc.querySelector(`[data-element='${UIElements.uiElementsMap[0].id}']`);
51 if (uiElement.style.backgroundColor !== null && uiElement.style.backgroundColor !== '')
52 webViewerData.defaultBackgroundColor = uiElement.style.backgroundColor;
53};
54
55// Customize the webviewer left panel.
56const customizeUI = () => {
57 const { UI } = webViewerData.instance;
58
59 // Enable the customizable UI feature flag.
60 UI.enableFeatureFlag(UI.FeatureFlags.CUSTOMIZABLE_UI);
61
62 // Enable all UI elements initially.
63 UI.enableAllElements();
64
65 // Fit the page to the viewer width.
66 UI.setFitMode(UI.FitMode.FitPage);
67
68 // Set the layout to single page mode.
69 UI.setLayoutMode(UI.LayoutMode.Single);
70
71 // Keep the page navigation component on screen all the time.
72 UI.disableFadePageNavigationComponent();
73
74 // Enable the annotation toolbar group.
75 UI.enableElements(['toolbarGroup-Annotate']);
76
77 // Close the tab panel (if it's open) for refreshment.
78 UI.closeElements([UIElements.tabPanel.dataElement]);
79
80 // Get the list of registered panels in the webviewer.
81 UIElements.viewerPanels = UI.getPanels();
82
83 // Find the Tab Panel to modify. The customize toolbar sub-panel will be added to this Tab panel.
84 UIElements.tabPanel.handle = UIElements.viewerPanels.find((panel) => panel.dataElement === UIElements.tabPanel.dataElement);
85
86 // Register the customize toolbar sub-panel.
87 RegisterCustomizeToolbarPanel(webViewerData.instance);
88
89 // Add the new customize toolbar sub-panel to list of sub-panels under the Tab Panel.
90 UIElements.customizeToolbarPanel.handle = { render: UIElements.customizeToolbarPanel.dataElement };
91 UIElements.tabPanel.handle.panelsList = [UIElements.customizeToolbarPanel.handle, ...UIElements.tabPanel.handle.panelsList];
92
93 UI.openElements([UIElements.tabPanel.dataElement]);
94};
95
96// Register the customize toolbar sub-panel.
97const RegisterCustomizeToolbarPanel = () => {
98 UIElements.customizeToolbarPanel.render = UIElements.createCustomizeToolbarPanelElements();
99 webViewerData.instance.UI.addPanel({
100 dataElement: UIElements.customizeToolbarPanel.dataElement,
101 location: 'left',
102 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>',
103 title: 'Customize Toolbar',
104 render: () => UIElements.customizeToolbarPanel.render,
105 });
106};
107
108// Enable or disable a UI element visibility.
109//Made global to be accessible in ui-elements.js.
110window.toggleElementVisibility = (element) => {
111 (webViewerData.instance.UI.isElementDisabled(element.id)) ?
112 webViewerData.instance.UI.enableElements([element.id]) :
113 webViewerData.instance.UI.disableElements([element.id]);
114};
115
116// Handle mouse over event, either for a checkbox or label control:
117// - change cursor to pointer
118// - toggle the UI element highlight
119window.controlOnMouseOver = (control, element) => {
120 control.style.cursor = 'pointer';
121
122 // Open the menu overlay when mouse is over the download or print button checkbox/label.
123 if (element.id === 'downloadButton' || element.id === 'printButton') {
124 if (webViewerData.instance.UI.isElementDisabled('menuOverlay'))
125 webViewerData.instance.UI.enableElements('menuOverlay');
126
127 if (!webViewerData.instance.UI.isElementOpen('menuOverlay'))
128 webViewerData.instance.UI.openElements('menuOverlay');
129 }
130
131 toggleElementHighlight(element);
132};
133
134// Handle mouse leave event, either for a checkbox or label control:
135// - change cursor to default
136// - toggle the UI element highlight
137window.controlOnMouseLeave = (control, element) => {
138 control.style.cursor = 'default';
139
140 // Close the menu overlay when mouse leaves the download or print button checkbox/label.
141 if (element.id === 'downloadButton' || element.id === 'printButton') {
142 if (webViewerData.instance.UI.isElementDisabled('menuOverlay'))
143 webViewerData.instance.UI.enableElements('menuOverlay');
144
145 if (webViewerData.instance.UI.isElementOpen('menuOverlay'))
146 webViewerData.instance.UI.closeElements('menuOverlay');
147 }
148
149 toggleElementHighlight(element);
150};
151
152// Highlight or reset highlight of a UI element.
153window.toggleElementHighlight = (element) => {
154 let uiElement = webViewerData.windowDoc.querySelector(`[data-element='${element.id}']`);
155 if (uiElement !== null) {
156 if (uiElement.style.backgroundColor === 'orange')
157 uiElement.style.backgroundColor = webViewerData.defaultBackgroundColor;
158 else
159 uiElement.style.backgroundColor = 'orange';
160 }
161};
162
163// Helper function to load the ui-elements.js script.
164function loadUIElementsScript() {
165 return new Promise((resolve, reject) => {
166 if (window.UIElements) {
167 console.log('UIElements already loaded');
168 resolve();
169 return;
170 }
171
172 const script = document.createElement('script');
173 script.src = '/showcase-demos/toolbar-customization/ui-elements.js';
174 script.onload = function () {
175 console.log('✅ UIElements script loaded successfully');
176 resolve();
177 };
178 script.onerror = function () {
179 console.error('Failed to load UIElements script');
180 reject(new Error('Failed to load ui-elements.js'));
181 };
182 document.head.appendChild(script);
183 });
184}
185
186// Load UIElements script first, then initialize WebViewer.
187loadUIElementsScript().then(() => {
188 initializeWebViewer();
189}).catch((error) => {
190 console.error('Failed to load UIElements:', error);
191});
192
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.
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