Skip to content
ComPDF
New Release

Open-Source PDF SDK & AI Document Processing

Get the full self-hosted SDK and AI document processing on GitHub. One-click deploy to quickly build your document workflows.

Panels

Panels are the slide-in sidebars on the left and right of the viewer. This guide covers the built-in panels, the generic Panel shell, and the APIs to add, replace, and inspect panels.

UI APIs

UI.addPanel(panel)

Add a custom panel to the left or right side.

javascript
/**
 * @method UI.addPanel
 * @param {Object<PanelProperties>} panel
 *   @param {string} panel.dataElement            Unique id.
 *   @param {string} panel.location               'left' | 'right'
 *   @param {string | UI.renderCustomPanel} panel.render  Predefined panel name or () => HTMLElement
 */
UI.addPanel({
  dataElement: 'myPanel',
  location: 'right',
  render: () => {
    const el = document.createElement('div');
    el.textContent = 'My panel';
    return el;
  },
});

render may be either a predefined panel name (see UI.Panels) or a function returning an HTMLElement (rendered through the generic CustomElement host). addPanel accepts a Panel instance (calls toObject()) or a plain object, then appends to the store's genericPanels list.

UI.setPanels(panelList)

Replace the entire panel list.

javascript
/**
 * @method UI.setPanels
 * @param {array} panelList The new list of panels to use in the UI.
 */
UI.setPanels([ /* PanelProperties[] */ ]);

Each entry is normalized through Panel.toObject() if it is a Panel instance.

UI.getPanels()

Return the current panels.

javascript
/**
 * @method UI.getPanels
 * @return {Array<UI.Components.Panel | UI.Components.TabPanel>}
 */
const panels = UI.getPanels();

Returns deep-cloned entries wrapped in UI.Components.Panel instances.

UI.Components.Panel class

MemberSignaturePurpose
dataElementstring (get/set)The panel's data-element; setter re-syncs the store.
renderstring|function (get/set)Render spec; setter re-syncs the store.
location'left'|'right' (get/set)Side; invalid → 'right'; setter re-syncs the store.
setLocation(location)(location: string) => voidExplicitly set the side.
delete()() => voidRemove the panel from the store.

Each mutation calls resetPanels() then setGenericPanels(panels) on the store.

Built-in panels

The default genericPanels list (9 entries):

dataElementLocationPurpose
leftPanelleft (full-height)Tabbed sidebar: thumbnails, outlines, annotations, layers, signatures, search.
rightPanelrightForm-field properties (General / Appearance / Preferences tabs).
stylePanelrightAnnotation & measurement properties.
pageModePanelrightPage display mode (single/double, scroll direction).
stampPanelrightStamp picker (Standard / Dynamic / Custom).
linkPanelrightLink-annotation properties.
contentEditorPanelrightContent-editor selection properties.
colorSeparationPanelrightColor-separation view.
redactionPanelrightRedaction-mark properties.

Left panel tabs

Switched by UI.setActiveElementTab('leftPanel', tab):

Tab constantContents
ThumbnailsButton (THUMBS)Page thumbnails — the .thumbnail-view mount target handed to core.initializeViewer.
OutlinesButton (OUTLINE)Bookmark / table-of-contents tree.
AnnotationButton (ANNOTATION_TAB)Annotation list (header + content).
LayersButton (LAYER)PDF layer visibility.
SignatureButton (SIGNATURE_TAB)Signature list.
SearchButton (SEARCH_TAB)Find bar.

Right panel tabs

UI.setActiveElementTab('rightPanel', tab):

Tab constantContents
GeneralField name, button text, visibility, required/indicator flags.
AppearanceFill color, font color/family/style/size (hidden for signature fields).
PreferenceAlignment, default value, multi-line, button style, options (hidden for signature fields).

The generic Panel shell

All panels render through components/Panel/Panel.vue — a fixed-position slide-in container (.left / .right, .mobile, .full, .closed uses translateX/translateY). It reads isOpen / isDisabled from useViewer.isElementOpen / isElementDisabled(dataElement), reserves panelSpace (260px when a side has an open panel) so DocumentContainer can shrink, and is 260px wide on desktop / 100vw on mobile.

Mounting strategy

The root App/index.vue renders every panel from useViewer.getGenericPanels via v-for, wrapping each in the Panel shell. The inner component is resolved three ways:

  • Eager (NoLazyComponents) for stylePanel, leftPanel, rightPanel, linkPanel, colorSeparationPanel, contentEditorPanel, redactionPanel.
  • Lazy (LazyLoadComponents, defineAsyncComponent) for pageModePanel, stampPanel, and CustomModal.
  • <CustomElement> for any user-supplied render function (custom panels).

The eager/lazy names are defined in constants/panel.js (noLazyPanelNames / panelNames).

Examples

Add and open a custom left panel

javascript
UI.addPanel({
  dataElement: 'commentsPanel',
  location: 'left',
  render: () => {
    const el = document.createElement('div');
    el.className = 'comments';
    el.innerHTML = '<h3>Comments</h3><ul><li>None yet</li></ul>';
    return el;
  },
});
UI.openElement('commentsPanel');

Move a panel to the other side

javascript
const [panel] = UI.getPanels().filter(p => p.dataElement === 'myPanel');
panel.setLocation('left');

Remove a panel

javascript
const [panel] = UI.getPanels().filter(p => p.dataElement === 'myPanel');
panel.delete();

Replace all panels

javascript
UI.setPanels([
  { dataElement: 'leftPanel', location: 'left', render: 'leftPanel' },
  { dataElement: 'myPanel',   location: 'right', render: () => myEl },
]);