---
title: "Create custom overlay in JavaScript PDF viewer | Nutrient"
canonical_url: "https://www.nutrient.io/guides/web/customizing-the-interface/creating-custom-overlay-items/"
md_url: "https://www.nutrient.io/guides/web/customizing-the-interface/creating-custom-overlay-items.md"
last_updated: "2026-05-14T16:53:43.944Z"
description: "Custom overlay items are user-generated DOM Nodes that are rendered in a page at a given position and add custom functionality to Nutrient Web SDK."
---

# Custom overlays in our viewer

[Custom overlay items](https://www.nutrient.io/api/web/NutrientViewer.CustomOverlayItem.html) are user-generated DOM `Node`s that are rendered in a page at a given position and add custom functionality to Nutrient Web SDK. For example, they can be used to add images, videos, or complex widgets written either in plain JavaScript or with your framework of choice.

[Try for Free](https://www.nutrient.io/sdk/web/getting-started.md)

[Launch Demo](https://www.nutrient.io/demo/pdf-overlays)

Custom overlay items are not part of the PDF spec and are therefore never persisted in the PDF document or database by Nutrient Web SDK.

## Creating a custom overlay item

A custom overlay item is a simple instance of [`NutrientViewer.CustomOverlayItem`](https://www.nutrient.io/api/web/NutrientViewer.CustomOverlayItem.html). To create this instance, we need to build our _item_ in JavaScript first.

To start, we are going to create a sample `video` item. Such a widget could, for example, be used to provide instructions on how to fill out a PDF form:

### ES6+

```js

const videoWidget = document.createElement("div");
videoWidget.innerHTML = `
  <video width="400" controls>
    <source src="https://www.nutrient.io/_astro/media/guides/web/customizing-the-interface/creating-custom-overlay-items/nutrient-logo.mp4" type="video/mp4">
    Your browser does not support HTML5 video.
  </video>
`;

```

### JAVASCRIPT

```js

const videoWidget = document.createElement("div");
videoWidget.innerHTML =
  '\
  <video width="400" controls>\
    <source src="https://www.nutrient.io/_astro/media/guides/web/customizing-the-interface/creating-custom-overlay-items/nutrient-logo.mp4" type="video/mp4"> \
    Your browser does not support HTML5 video. \
  </video> \
';

```

Once we have our DOM `Node`, we can easily create the item:

### ES6+

```js

const item = new NutrientViewer.CustomOverlayItem({
  id: "video-instructions",
  node: videoWidget,
  pageIndex: 0,
  position: new NutrientViewer.Geometry.Point({ x: 50, y: 600 })
});

```

### JAVASCRIPT

```js

var item = new NutrientViewer.CustomOverlayItem({
  id: "video-instructions",
  node: videoWidget,
  pageIndex: 0,
  position: new NutrientViewer.Geometry.Point({ x: 50, y: 600 })
});

```

Finally, we can insert the item into the PDF document using the [`Instance#setCustomOverlayItem`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#setCustomOverlayItem) method:

### ES6+

```js

instance.setCustomOverlayItem(item);

```

### JAVASCRIPT

```js

instance.setCustomOverlayItem(item);

```

The video widget in the PDF document.

This is how the above snippets look once put together:

### ES6+

```js

const videoWidget = document.createElement("div");
videoWidget.innerHTML = `
  <video width="400" controls>
    <source src="https://www.nutrient.io/_astro/media/guides/web/customizing-the-interface/creating-custom-overlay-items/nutrient-logo.mp4" type="video/mp4">
    Your browser does not support HTML5 video.
  </video>
`;
const item = new NutrientViewer.CustomOverlayItem({
  id: "video-instructions",
  node: videoWidget,
  pageIndex: 0,
  position: new NutrientViewer.Geometry.Point({ x: 50, y: 600 })
});
instance.setCustomOverlayItem(item);

```

### JAVASCRIPT

```js

const videoWidget = document.createElement("div");
videoWidget.innerHTML =
  '\
  <video width="400" controls>\
    <source src="https://www.nutrient.io/_astro/media/guides/web/customizing-the-interface/creating-custom-overlay-items/nutrient-logo.mp4" type="video/mp4"> \
    Your browser does not support HTML5 video. \
  </video> \
';
var item = new NutrientViewer.CustomOverlayItem({
  id: "video-instructions",
  node: videoWidget,
  pageIndex: 0,
  position: new NutrientViewer.Geometry.Point({ x: 50, y: 600 })
});
instance.setCustomOverlayItem(item);

```

[`Instance#setCustomOverlayItem`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#setCustomOverlayItem) can also be used to update existing overlay items by `id`.

For example, we could move the item to page `2`:

### ES6+

```js

const updatedItem = item.set("pageIndex", 1);
instance.setCustomOverlayItem(updatedItem);

```

### JAVASCRIPT

```js

var updatedItem = item.set("pageIndex", 1);
instance.setCustomOverlayItem(updatedItem);

```

We could also change the `node`:

### ES6+

```js

const message = document.createTextNode("instructions");
videoWidget.appendChild(message);

```

### JAVASCRIPT

```js

var message = document.createTextNode("instructions");
videoWidget.appendChild(message);

```

Notice that in the last example, we didn’t set the `node` property or call `setCustomOverlayItem`. Unlike with the first example, we can mutate the `node` directly, and any change to it will be reflected on the page without the need to call `setCustomOverlayItem` again.

## Removing custom overlay items

Custom overlay items can be removed at any time using the [`Instance#removeCustomOverlayItem`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#removeCustomOverlayItem) API method, which accepts the `id` of the item to be removed:

### ES6+

```js

instance.removeCustomOverlayItem("video-instructions");

```

### JAVASCRIPT

```js

instance.removeCustomOverlayItem("video-instructions");

```

## Get notifications when items are rendered or removed

When a custom overlay item is shown on the page for the first time (rendered), it executes an optional `onAppear` callback. This callback is defined at creation time, like so:

### ES6+

```js

const item = new NutrientViewer.CustomOverlayItem({
  id: "video-instructions",
  node: videoWidget,
  pageIndex: 0,
  position: new NutrientViewer.Geometry.Point({ x: 50, y: 600 }),
  onAppear: () => {
    console.log("video instructions rendered!");
  }
});

```

### JAVASCRIPT

```js

var item = new NutrientViewer.CustomOverlayItem({
  id: "video-instructions",
  node: videoWidget,
  pageIndex: 0,
  position: new NutrientViewer.Geometry.Point({ x: 50, y: 600 }),
  onAppear: function() {
    console.log("video instructions rendered!");
  }
});

```

Keep in mind that `onAppear` is invoked only when the page renders for the first time, so if we insert an item on page `2`, the callback will be invoked only when we visit that page.

Similar to what happens with `onAppear`, custom overlay items invoke an optional `onDisappear` callback when the overlay item is removed.
---

## Related pages

- [Create a custom toolbar in our JavaScript PDF viewer](/guides/web/user-interface/create-a-toolbar.md)
- [User interface customization in our JavaScript PDF viewer](/guides/web/user-interface.md)
- [PDF form field date and time picker](/guides/web/user-interface/date-and-time-picker.md)
- [Create and customize redactions in our PDF viewer](/guides/web/user-interface/redaction.md)
- [Form Designer: Create and edit PDF form fields using JavaScript](/guides/web/user-interface/form-designer.md)
- [Right-to-left](/guides/web/user-interface/rtl-languages.md)
- [Localization: Updating languages in our JavaScript PDF viewer](/guides/web/features/localization.md)
- [Customizing the search UI in our PDF viewer toolbar](/guides/web/user-interface/search.md)
- [User interface troubleshooting](/guides/web/user-interface/troubleshooting.md)
- [View state in our JavaScript PDF viewer](/guides/web/customizing-the-interface/viewstate.md)

