> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/ui-customization/customizing-popup.md).

# Customize Popups and the Popup API in WebViewer Using JavaScript

Learn how to customize popups in WebViewer UI with this comprehensive guide. Discover different types of popups and how to add, modify, or delete items easily using the provided APIs. The Apryse Web S

The popups in WebViewer UI are small floating menus.

In WebViewer UI, there are 4 types of popups:

* [context menu popup](https://sdk.apryse.com/api/web/UI.html#contextMenuPopup__anchor); appears on right click of a blank space

![](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2Fgit-blob-9e73f7be429140bfeb5620ed7cf292a6fc5a7903%2F8ca5fabff478f838b437f0219c628ae2e9c85907-254x56.png?alt=media)

* [text popup](https://sdk.apryse.com/api/web/UI.html#textPopup__anchor); appears on highlight of a text when using select tool

![](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2Fgit-blob-fb6da41e667559c99042c659945f9ec655605276%2F061ba1e2768d7abe8587a1621d37154f57adf8ad-410x174.png?alt=media)

* [annotation popup](https://sdk.apryse.com/api/web/UI.html#annotationPopup__anchor); appears on selection of annotation(s)

![](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2Fgit-blob-50c2a597f4605c66ae1558f1c6a95079290f74ac%2Fb3887a1177701887b15fce7d5073ef9021212983-239x253.png?alt=media)

* [content overlay popup](https://sdk.apryse.com/api/web/UI.html#setAnnotationContentOverlayHandler__anchor); appears on hover of annotation(s)

![](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2Fgit-blob-3e4a21fe7a0cdae5a26edd16c783c31688066fe3%2Ffb017c08bd3fb521fcb72f4b603e0b96c5f90cb6-786x195.png?alt=media)

There are a number of ways you may want to customize Popups. To name a few:

* [Adding items](#adding-items)
* [Modifying items](#modifying-items)
* [Deleting items](#deleting-items)

The WebViewer UI provides API's to easily handle each of these cases and more.

## Get items

The unique identifier of the items in the popup can be retrieved using the [getItems API](https://sdk.apryse.com/api/web/UI.Popup.html#getItems__anchor). It returns an array of objects where each object contains a key that denotes the dataElement.

## Adding items

Adding items can be done using the [add API](https://sdk.apryse.com/api/web/UI.Popup.html#add__anchor). The type of items to add can be found in the [list of items](/web/ui-customization/modular-ui/items.md) for Modular UI.

#### Add new items at beginning of the popup

To add new items at beginning of the popup, do not provide a second parameter to the add function.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    instance.UI.contextMenuPopup.add({
      type: 'actionButton',
      label: 'some-label',
      onClick: () => console.log('clicked'),
    });
  });
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    instance.contextMenuPopup.add({
      type: 'actionButton',
      label: 'some-label',
      onClick: () => console.log('clicked'),
    });
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Add new items at a specific location in the popup

There are 2 ways to do this.

Option one:

* If you know the specific element you want it to be after then you can provide a [valid dataElement string](/web/ui-customization/hiding-elements.md#hiding-by-finding-data-element-attribute-values) as a second parameter. This will insert the new item(s) after the specified data element.

Option two:

* If you know the index where you want to add it (for example as the last button) then you can get the list of data elements in the popup using the [getItems API](https://sdk.apryse.com/api/web/UI.Popup.html#getItems__anchor). Then retrieve the data element from the item at that index.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    // insert after the last element in the popup
    const contextMenuItems = instance.UI.contextMenuPopup.getItems();
    const lastItem = contextMenuItems[contextMenuItems.length - 1];

    instance.UI.contextMenuPopup.add({
      type: 'actionButton',
      label: 'Get selected text',
      onClick: () => console.log(instance.Core.documentViewer.getSelectedText()),
    },
    lastItem.dataElement);
  });
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    // insert after the last element in the popup
    const contextMenuItems = instance.contextMenuPopup.getItems();
    const lastItem = contextMenuItems[contextMenuItems.length - 1];

    instance.contextMenuPopup.add({
      type: 'actionButton',
      label: 'Get selected text',
      onClick: () => console.log(instance.docViewer.getSelectedText()),
    },
    lastItem.dataElement);
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Modifying items

Existing items can be modified using [updateElements](https://sdk.apryse.com/api/web/UI.html#updateElement__anchor). The items in the popup can be replaced using [update](https://sdk.apryse.com/api/web/UI.Popup.html#update__anchor).

#### Update existing elements' properties

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    // Updating existing sticky tool button in context menu popup with new label and new on click handler
    instance.UI.updateElement("stickyToolButton", {label: 'new-label', onClick: () => console.log('clicked')});
  });
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    // Updating existing sticky tool button in context menu popup with new label and new on click handler
    instance.updateElement("stickyToolButton", {label: 'new-label', onClick: () => console.log('clicked')});
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Replace existing elements

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    // replace existing items with a new array of items
    instance.UI.contextMenuPopup.update([
      {
        type: 'actionButton',
        label: '1',
        onClick: () => console.log('clicked'),
      },
      {
        type: 'actionButton',
        label: '2',
        onClick: () => console.log('clicked'),
      },
    ]);
  });
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    // replace existing items with a new array of items
    instance.contextMenuPopup.update([
      {
        type: 'actionButton',
        label: '1',
        onClick: () => console.log('clicked'),
      },
      {
        type: 'actionButton',
        label: '2',
        onClick: () => console.log('clicked'),
      },
    ]);
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Update ordering of elements in the popup

This can be done by:

1. Get the list of data elements in the popup using the [getItems API](https://sdk.apryse.com/api/web/UI.Popup.html#getItems__anchor)
2. Modify ordering of the elements in the list retrieved from step 1.
3. call [update](https://sdk.apryse.com/api/web/UI.Popup.html#update__anchor)

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    const contextMenuItems = instance.UI.contextMenuPopup.getItems();
    const newArray = contextMenuItems.reverse();
    instance.UI.contextMenuPopup.update(newArray);
  });
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    const contextMenuItems = instance.contextMenuPopup.getItems();
    const newArray = contextMenuItems.reverse();
    instance.contextMenuPopup.update(newArray);
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Deleting items

Items in the popup can be deleted using the using [disableElements](/web/ui-customization/hiding-elements.md).

## Adds a custom overlay to annotation on hover

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    instance.UI.setAnnotationContentOverlayHandler(annotation => { 
      const div = document.createElement('div'); 
      div.appendChild(document.createTextNode(`Created by: ${annotation.Author}`)); 
      div.appendChild(document.createElement('br')); 
      div.appendChild(document.createTextNode(`Created on ${annotation.DateCreated}`)); 
      return div; 
    });
  });
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(...)
  .then(function(instance) {
    instance.setAnnotationContentOverlayHandler(annotation => { 
      const div = document.createElement('div'); 
      div.appendChild(document.createTextNode(`Created by: ${annotation.Author}`)); 
      div.appendChild(document.createElement('br')); 
      div.appendChild(document.createTextNode(`Created on ${annotation.DateCreated}`)); 
      return div; 
    });
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Customizing Popups with the Modular UI

When using the Modular UI, you can continue using existing [Popup APIs](/web/ui-customization/customizing-popup.md). As of `11.8`, you can also customize Popups using [configuration files](/web/ui-customization/modular-ui/ui-import-and-export.md), making it easy to audit your current customizations at a glance or maintain different variants for different use cases.

To recap, there are three Popups you can customize using these APIs:

* [AnnotationPopup](https://sdk.apryse.com/api/web/UI.html#.annotationPopup__anchor): Appears when you select an annotation.
* [ContextMenuPopup](https://sdk.apryse.com/api/web/UI.html#.contextMenuPopup__anchor): Appears when you right-click anywhere on the viewer container.
* [TextPopup](https://sdk.apryse.com/api/web/UI.html#.textPopup__anchor): Appears when you select text.

For example, you may want to add a `ToolButton` to the `ContextMenuPopup`, so users can quickly access commonly used tools:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```javascript
WebViewer(...)
  .then(function(instance) {
    instance.UI.contextMenuPopup.add({
      dataElement: 'rectangleToolButtonInContextMenu',
      type: 'toolButton',
      toolName: 'AnnotationCreateRectangle'
    });
    
    // Alternatively, you can use the constructor to create the new button.
    const ellipseToolButton = new instance.UI.Components.ToolButton({
    dataElement: 'ellipseToolButtonInContextMenu',
    toolName: 'AnnotationCreateEllipse',
    });
    
    // And then add it
    instance.UI.contextMenuPopup.add([ellipseToolButton]);
  });
```

{% endcode %}
{% endtab %}
{% endtabs %}

Notice that we used a `ToolButton` as defined in the [items documentation](/web/ui-customization/modular-ui/items.md#tool-buttons). Popups in the Modular UI support the following item types:

* [ToolButton](/web/ui-customization/modular-ui/items.md#tool-buttons)
* [ToggleButton](/web/ui-customization/modular-ui/items.md#toggle-element-buttons)
* [CustomButton](/web/ui-customization/modular-ui/items.md#custom-buttons)
* [StatefulButton](/web/ui-customization/modular-ui/items.md#stateful-buttons)
* [CustomElement](/web/ui-customization/modular-ui/items.md#custom-elements)

### Customizing via the configuration file

Starting in `11.8`, when you call [exportModularComponents](https://sdk.apryse.com/api/web/UI.html#.exportModularComponents), you will see a new key in the JSON for the three customizable Popups:

{% tabs %}
{% tab title="JSON" %}
{% code lineNumbers="true" %}

```json
// Other components removed for ease of readability.
{
    "modularComponents": {},
    "modularHeaders": {},
    "panels": {},
    "flyouts": {},
    "popups": {
        "annotationPopup": [
            {
                "dataElement": "viewFileButton"
            },
            {
                "dataElement": "annotationCommentButton"
            },
            {
                "dataElement": "annotationStyleEditButton"
            }
        ],
        "textPopup": [
            {
                "dataElement": "copyTextButton"
            },
            {
                "dataElement": "textHighlightToolButton"
            },
            {
                "dataElement": "textUnderlineToolButton"
            },
            {
                "dataElement": "textSquigglyToolButton"
            },
            {
                "dataElement": "textStrikeoutToolButton"
            },
            {
                "dataElement": "textRedactToolButton"
            },
            {
                "dataElement": "linkButton"
            }
        ],
        "contextMenuPopup": [
            {
                "dataElement": "panToolButton"
            },
            {
                "dataElement": "stickyToolButton"
            },
            {
                "dataElement": "highlightToolButton"
            },
            {
                "dataElement": "freeHandToolButton"
            },
            {
                "dataElement": "freeHandHighlightToolButton"
            },
            {
                "dataElement": "freeTextToolButton"
            },
            {
                "dataElement": "markInsertTextToolButton"
            },
            {
                "dataElement": "markReplaceTextToolButton"
            }
        ]
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Each Popup will be a key in the JSON, with a list of the buttons it contains. The `dataElements` point to buttons the UI ships by default, such as the `annotationStyleEditButton` which toggles the Style Panel.

{% hint style="info" %}
**Why are there more items for each Popup than I can see in the UI?**

The items for each Popup may not match what you see in all circumstances in the UI. For example, the `AnnotationPopup` includes the `annotationGroupButton` that only renders when you select multiple annotations.
{% endhint %}

As with any custom component in the Modular UI, if you pass custom handlers or render functions, make sure those functions are added to the `FunctionMap` when importing your configuration. See the [FunctionMap guide](/web/ui-customization/modular-ui/ui-import-and-export.md#add-a-function-map) for more in-depth examples.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/ui-customization/customizing-popup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
