> 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/core.md).

# Building your own UI

Enhance your document processing with Core, the WebViewer engine that manages rendering, annotations, and more. Explore namespaces like DocumentViewer and AnnotationManager for seamless integration. C

If you do not want to use the default WebViewer UI and you want to build your own UI, you can do so by interacting with the "Core" library.

The core library is the engine that the WebViewer UI interacts with. This library can be loaded independently of the WebViewer UI, allowing you to build your own UI by using the APIs that the core library exposes.

## Loading the core library

If you want to load just the core library, you can do so by including a script tag that references the `webviewer-core.min.js` file included in the WebViewer package.

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

```html
<script src="/webviewer/core/webviewer-core.min.js"></script>
```

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

{% hint style="info" %}
This is all that is required to load the core library. You do not need to call the WebViewer constructor to load the core library.
{% endhint %}

Loading this file will expose the [`Core`](https://sdk.apryse.com/api/web/Core.html) namespace to the window (accessible via `window.Core`). This namespace contains all the APIs you need to build your own UI.

## Configuring the core library

The core library has several other dependencies that it needs to load, including other JS files and WASM files. You must tell the core library where to find these files. To do so, you can call the `setWorkerPath` function at the beginning of your application. This function accepts a path that should point to the `core` folder in the WebViewer package.

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

```js
Core.setWorkerPath('/path/to/core/');
```

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

## Loading and rendering a document

The Core namespace exposes a `DocumentViewer` class, which is the class that manages the rendering of documents to the DOM. This class requires you to set the DOM elements that you want the document to be rendered to.

In your HTML, you need to create two divs. The first div, called the "Scroll view", is the outermost container that will house the viewer. If the document you load exceeds the height of this container, the container will become scrollable.

The second div is the "Viewer element". This div is used to render the actual document to. The viewer element must be nested in the scroll view element.

Below is an example of what the HTML structure could look like:

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

```html
<div id='scroll-view' style='max-height: 600px; height: 600px; width: 100%;'>
	<div id='viewer'></div>
</div>
```

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

You can now create an instance of the DocumentViewer class, and provide it the two containers using the following APIs:

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

```js
const docViewer = new Core.DocumentViewer();  
docViewer.setScrollViewElement(document.getElementById('scroll-view'));  
docViewer.setViewerElement(document.getElementById('viewer'));
```

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

To load a document, we can now call the `docViewer.loadDocument` API and pass in a file path or a blob.

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

```js
docViewer.loadDocument('/path/to/document.pdf');
```

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

## Adding your own UI elements

Once you have the core library configured and rendering a document, we can start to interact with the document by using more of the exposed APIs.

This process will typically involve you building out your own UI elements, and calling Core apis when those elements are clicked.

For example, you may want to add zoom controls to your UI. You could do this by adding a "Zoom in" and "Zoom out" button, and calling `docViewer.zoomTo` when either of them are clicked.

That might look something like this:

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

```js
const docViewer = new Core.DocumentViewer();  
// Assuming we have a button with the ID "zoom-in-button"
document.getElementById('zoom-in-button').addEventListener('click', () => {  
	docViewer.zoomTo(docViewer.getZoom() + 0.25);  
});
// Assuming we have a button with the ID "zoom-out-button"
document.getElementById('zoom-out-button').addEventListener('click', () => {  
	docViewer.zoomTo(docViewer.getZoom() - 0.25);  
});
```

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

The process for other custom UI elements is the same, no matter what functionality you are looking to build.

There are many different APIs to interact with on the Core and DocumentViewer namespaces, which are all documented in our [API Documentation](https://sdk.apryse.com/api/web/Core.html).

## Annotation support

The process for building out an annotation UI is similar to building out other UI elements (as mentioned in the above section).

This will involve you setting up your UI, binding events to the UI elements, and calling Core APIs when buttons are pressed.

The easiest way to get started is to switch between different annotation tools when buttons are pressed or when certain events are fired.

The default tool for interacting with documents and annotations is called the `AnnotationEdit` tool. This tool lets you select text and edit annotations. Typically, you want this tool to be set by default when your UI is loaded. You can do that by calling `docViewer.setToolMode` after a document is loaded.

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

```js
const docViewer = new Core.DocumentViewer();
docViewer.addEventListener('documentLoaded', () => {  
	// enable default tool for text and annotation selection  
	docViewer.setToolMode(docViewer.getTool('AnnotationEdit'));  
});
```

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

We can also switch to other annotation tools by passing in different tool names to the `getTool` function used above. A full list of tools is available [here](https://sdk.apryse.com/api/web/Core.Tools.html).

For example, we could add a button that switches to the rectangle tool, which will allow the user to draw rectangle annotations on the document.

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

```js
const docViewer = new Core.DocumentViewer();
// Assuming a button with the ID "create-rectangle" exists
document.getElementById('create-rectangle').addEventListener('click', () => {  
	docViewer.setToolMode(docViewer.getTool('AnnotationCreateRectangle'));  
});

```

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

You can change the color, stroke width, and many other properties of the annotations by using the [`setStyles`](https://sdk.apryse.com/api/web/Core.Tools.Tool.html#setStyles) APIs.

For example, we could change the rectangle annotation to be red instead of black like so:

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

```js
const docViewer = new Core.DocumentViewer();
// Assuming a button with the ID "create-rectangle" exists
document.getElementById('create-rectangle').addEventListener('click', () => {  
	const tool = docViewer.getTool('AnnotationCreateRectangle')
	tool.setStyles({
		StrokeColor: new Core.Annotations.Color(255,0,0)
	})
	docViewer.setToolMode(tool);  
});
```

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

All the different styles that can be applied are documented [here](https://sdk.apryse.com/api/web/Core.Tools.Tool.html#setStyles). Each tool has different styles that can be applied, so make sure to reference the correct documentation for the tool you are editing.

## Further reading

You can find the core namespace reference in our [API documentation](https://sdk.apryse.com/api/web/Core.html). Here you can explore all the different classes and APIs available to help you build out your own UI. You can also reference other guides and code snippets throughout the WebViewer documentation. Many of these code snippets will reference `instance.Core` (returned by the WebViewer constructor), but you can edit these snippets to work for your own UI by just using the global `Core` namespace.

We also have a [sample repository](https://github.com/ApryseSDK/webviewer-custom-ui/) showing how to start building a custom UI using react.

You can also reference our [open source WebViewer UI repo](https://github.com/ApryseSDK/webviewer-ui) which uses all the same concepts as this guide.


---

# 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/core.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.
