> 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/annotation/customizing-tools.md).

# Customizing annotation tools

Learn how to customize tools in WebViewer UI with specific APIs for enabling/disabling, updating properties, extending built-in tools, and more. Enhance user experience with tailored tool functionalit

Customizing tools is little different from [customizing header items](/web/ui-customization/legacy-ui/customizing-header.md). In WebViewer UI, they are setup in a special way to be mapped to DocumentViewer's tool modes and grouped into [tool group buttons](/web/ui-customization/legacy-ui/customizing-header.md#toolgroupbutton). Thus, WebViewer UI provides specific APIs for customizing tools.

## Disabling/enabling tools

By default, WebViewer provides shortcuts for most of the tools. If you want users not to use certain tools, you should disable both the DOM element and the shortcut. You can do that with a single API, using one of the following:

* [enableTools](https://sdk.apryse.com/api/web/UI.html#enableTools__anchor)
* [disableTools](https://sdk.apryse.com/api/web/UI.html#disableTools__anchor)

And you can check if a tool is disabled using this API:

* [isToolDisabled](https://sdk.apryse.com/api/web/UI.html#isToolDisabled__anchor)

You can refer to the [full list of tool names](/web/annotation/annotations-and-tools.md#list-of-tool-names) for the values to pass to these functions.

For example,

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

```js
WebViewer(...)
  .then(instance => {
    instance.UI.disableTools([ 'AnnotationCreateSticky', 'AnnotationCreateFreeText' ]); // hides DOM element + disables shortcut
    console.log(instance.UI.isToolDisabled('AnnotationCreateSticky'));

    // re-enable every tool when no parameter is passed in
    instance.UI.enableTools();
  });
```

{% endcode %}
{% endtab %}

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

```js
WebViewer(...)
  .then(instance => {
    instance.disableTools([ 'AnnotationCreateSticky', 'AnnotationCreateFreeText' ]); // hides DOM element + disables shortcut
    console.log(instance.isToolDisabled('AnnotationCreateSticky'));

    // re-enable every tool when no parameter is passed in
    instance.enableTools();
  });
```

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

## Updating tool property

You can also update tool properties to customize the buttons on the header using [updateTool](https://sdk.apryse.com/api/web/UI.html#.updateTool):

* buttonImage
* buttonName
* buttonGroup
* tooltip

### Changing button icon

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

```js
WebViewer(...)
  .then(instance => {
    instance.UI.updateTool('AnnotationCreateSticky', {
      buttonImage: 'https://www.pdftron.com/favicon-32x32.png'
    });
  });
```

{% endcode %}

[UI.updateTool](https://sdk.apryse.com/api/web/UI.html#updateTool__anchor)
{% endtab %}

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

```js
WebViewer(...)
  .then(instance => {
    instance.updateTool('AnnotationCreateSticky', {
      buttonImage: 'https://www.pdftron.com/favicon-32x32.png'
    });
  });
```

{% endcode %}

[WebViewerInstance.updateTool](https://sdk.apryse.com/api/web/UI.html#.updateTool)
{% endtab %}
{% endtabs %}

### Changing button group

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

```js
WebViewer(...)
  .then(instance => {
    instance.UI.updateTool('AnnotationCreateRectangle', {
      buttonGroup: 'miscTools'
    });
  });
```

{% endcode %}

[UI.updateTool](https://sdk.apryse.com/api/web/UI.html#updateTool__anchor)
{% endtab %}

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

```js
WebViewer(...)
  .then(instance => {
    instance.updateTool('AnnotationCreateRectangle', {
      buttonGroup: 'miscTools'
    });
  });
```

{% endcode %}

[WebViewerInstance.updateTool](https://sdk.apryse.com/api/web/UI.html#updateTool__anchor)
{% endtab %}
{% endtabs %}

## Event when tool creates an annotation

WebViewer provides the [annotationAdded event](https://sdk.apryse.com/api/web/Core.Tools.GenericAnnotationCreateTool.html#event:annotationAdded__anchor) on most annotation tools which is fired when a new annotation is created with that tool.

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

```js
WebViewer(...)
  .then(instance => {
    const { documentViewer } = instance.Core;
    const tool = documentViewer.getTool('AnnotationCreateFreeText');

    // the tool is just a reference to the instance of a tool
    // it could also be something like:
    // const tool = new MyCustomTool(documentViewer);
    tool.addEventListener('annotationAdded', (annotation) => {
      annotation.FillColor = new Annotations.Color(255, 0, 0);
    });
  });
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html) [DocumentViewer.getTool](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getTool__anchor) [annotationAdded event](https://sdk.apryse.com/api/web/Core.Tools.GenericAnnotationCreateTool.html#event:annotationAdded__anchor)
{% endtab %}

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

```js
WebViewer(...)
  .then(instance => {
    const { docViewer } = instance;
    const tool = docViewer.getTool('AnnotationCreateFreeText');

    // the tool is just a reference to the instance of a tool
    // it could also be something like:
    // const tool = new MyCustomTool(docViewer);
    tool.on('annotationAdded', (annotation) => {
      annotation.FillColor = new Annotations.Color(255, 0, 0);
    });
  });
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [DocumentViewer.getTool](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getTool__anchor) [annotationAdded event](https://sdk.apryse.com/api/web/Core.Tools.GenericAnnotationCreateTool.html#event:annotationAdded__anchor)
{% endtab %}
{% endtabs %}

## Extending built in tools

WebViewer allows you to extend the behavior of tools by overriding certain functions on them. Common functions you might want to override include mouseLeftDown, mouseMove and mouseLeftUp among others.

As an example let's change the highlight tool so that when the user finishes highlighting, the highlight will turn cyan. To override a particular function on a tool we can set its value to a new function.

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

```js
WebViewer(...)
  .then(instance => {
    const { Tools } = instance.Core;
    // get a copy of the default mouse up function
    const highlightMouseUp = Tools.TextHighlightCreateTool.prototype.mouseLeftUp;
    // set it to our own function
    Tools.TextHighlightCreateTool.prototype.mouseLeftUp = function() {
      // just call the original function for now, passing all the arguments
      highlightMouseUp.apply(this, arguments);
    };
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html)
{% endtab %}

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

```js
WebViewer(...)
  .then(instance => {
    const { Tools } = instance;
    // get a copy of the default mouse up function
    const highlightMouseUp = Tools.TextHighlightCreateTool.prototype.mouseLeftUp;
    // set it to our own function
    Tools.TextHighlightCreateTool.prototype.mouseLeftUp = function() {
      // just call the original function for now, passing all the arguments
      highlightMouseUp.apply(this, arguments);
    };
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html)
{% endtab %}
{% endtabs %}

In the example code above we're just calling the original mouse up function that we saved as a variable. Just using that code there should be no visible change in the behavior of the highlight tool.

Let's change the color of the annotation now. All annotation tools have an "annotation" property which is the current annotation being created by the tool. It's created in mouseLeftDown, modified in mouseMove and removed from the tool in mouseLeftUp. This means we need to access it before the original mouseLeftUp function is called.

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

```js
WebViewer(...)
  .then(instance => {
    const { Tools } = instance.Core;
    const highlightMouseUp = Tools.TextHighlightCreateTool.prototype.mouseLeftUp;
    Tools.TextHighlightCreateTool.prototype.mouseLeftUp = function() {
      if (this.annotation) {
        this.annotation.StrokeColor = new Annotations.Color(0, 255, 255);
      }
      highlightMouseUp.apply(this, arguments);
    };
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html)
{% endtab %}

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

```js
WebViewer(...)
  .then(instance => {
    const { Tools } = instance;
    const highlightMouseUp = Tools.TextHighlightCreateTool.prototype.mouseLeftUp;
    Tools.TextHighlightCreateTool.prototype.mouseLeftUp = function() {
      if (this.annotation) {
        this.annotation.StrokeColor = new Annotations.Color(0, 255, 255);
      }
      highlightMouseUp.apply(this, arguments);
    };
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html)
{% endtab %}
{% endtabs %}

If you try this code you'll see that it almost works, however you need to click the page again for the annotation to be redrawn in the new color. To fix this we'll need to redraw the annotation inside the tool so that it's updated right away.

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

```js
WebViewer(...)
  .then(instance => {
    const { Tools, annotationManager } = instance.Core;
    const highlightMouseUp = Tools.TextHighlightCreateTool.prototype.mouseLeftUp;
    Tools.TextHighlightCreateTool.prototype.mouseLeftUp = function() {
      if (this.annotation) {
        this.annotation.StrokeColor = new Annotations.Color(0, 255, 255);
        annotationManager.redrawAnnotation(this.annotation);
      }
      highlightMouseUp.apply(this, arguments);
    };
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html) [AnnotationManager.redrawAnnotation](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#redrawAnnotation__anchor)
{% endtab %}

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

```js
WebViewer(...)
  .then(instance => {
    const { Tools, annotManager } = instance;
    const highlightMouseUp = Tools.TextHighlightCreateTool.prototype.mouseLeftUp;
    Tools.TextHighlightCreateTool.prototype.mouseLeftUp = function() {
      if (this.annotation) {
        this.annotation.StrokeColor = new Annotations.Color(0, 255, 255);
        annotManager.redrawAnnotation(this.annotation);
      }
      highlightMouseUp.apply(this, arguments);
    };
  })
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [AnnotationManager.redrawAnnotation](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#redrawAnnotation__anchor)
{% endtab %}
{% endtabs %}

Now the highlight should change colors right after it's created. As mentioned earlier you can override several different functions on tools and it should work similarly to the example above.


---

# 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/annotation/customizing-tools.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.
