# Create custom annotation toggle button

This guide demonstrates how to create a custom toggle button in the Nutrient Web SDK toolbar that enables users to show or hide all annotations in a PDF document.

> **Live demo** — Try the [custom annotation toggle](https://www.nutrient.io/demo/sandbox?p=eyJ2IjoxLCJzZXR0aW5ncyI6eyJmaWxlTmFtZSI6ImJhc2ljLnBkZiJ9LCJjc3MiOiIvKiBBZGQgeW91ciBDU1MgaGVyZSAqL1xuIiwianMiOiJsZXQgYW5ub3RhdGlvbnNIaWRkZW4gPSB0cnVlO1xuXG5OdXRyaWVudFZpZXdlci5sb2FkKHtcbiAgLi4uYmFzZU9wdGlvbnMsXG4gIHRoZW1lOiBOdXRyaWVudFZpZXdlci5UaGVtZS5EQVJLLFxuICB0b29sYmFySXRlbXM6IFsuLi5OdXRyaWVudFZpZXdlci5kZWZhdWx0VG9vbGJhckl0ZW1zXSxcbn0pLnRoZW4oYXN5bmMgKGluc3RhbmNlKSA9PiB7XG4gIGNvbnN0IHRvZ2dsZUFubm90YXRpb25zQnV0dG9uID0ge1xuICAgIHR5cGU6IFwiY3VzdG9tXCIsXG4gICAgaWQ6IFwidG9nZ2xlLWFubm90YXRpb25zXCIsXG4gICAgdGl0bGU6IFwiVG9nZ2xlIEFubm90YXRpb25zXCIsXG4gICAgb25QcmVzczogYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdFBhZ2VzID0gaW5zdGFuY2UudG90YWxQYWdlQ291bnQ7XG4gICAgICBjb25zb2xlLmxvZyhcIlRvdGFsIFBhZ2VzOiBcIiwgdFBhZ2VzKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdFBhZ2VzOyBpKyspIHtcbiAgICAgICAgY29uc3QgYW5ubyA9IGF3YWl0IGluc3RhbmNlLmdldEFubm90YXRpb25zKGkpO1xuICAgICAgICBjb25zb2xlLmxvZyhcIjIgLSBBbm5vdGF0aW9uczogXCIsIGFubm8pO1xuICAgICAgICBjb25zb2xlLmxvZyhcInRvdGFsIGFubm90YXRpb24gaW4gZWFjaCBwYWdlXCIsIGFubm8uc2l6ZSk7XG4gICAgICAgIGlmIChhbm5vdGF0aW9uc0hpZGRlbiA9PT0gdHJ1ZSkge1xuICAgICAgICAgIGFubm8uZm9yRWFjaChhc3luYyAoYW5ubykgPT4ge1xuICAgICAgICAgICAgY29uc3QgdXBkYXRlYW5ubyA9IGFubm8uc2V0KFwibm9WaWV3XCIsIHRydWUpO1xuICAgICAgICAgICAgYXdhaXQgaW5zdGFuY2UudXBkYXRlKHVwZGF0ZWFubm8pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGFubm8uZm9yRWFjaChhc3luYyAoYW5ubykgPT4ge1xuICAgICAgICAgICAgY29uc3QgdXBkYXRlYW5ubyA9IGFubm8uc2V0KFwibm9WaWV3XCIsIGZhbHNlKTtcbiAgICAgICAgICAgIGF3YWl0IGluc3RhbmNlLnVwZGF0ZSh1cGRhdGVhbm5vKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgYW5ub3RhdGlvbnNIaWRkZW4gPSAhYW5ub3RhdGlvbnNIaWRkZW47XG4gICAgfSxcbiAgfTtcblxuICBpbnN0YW5jZS5zZXRUb29sYmFySXRlbXMoKGl0ZW1zKSA9PiB7XG4gICAgaXRlbXMucHVzaCh0b2dnbGVBbm5vdGF0aW9uc0J1dHRvbik7XG4gICAgcmV0dXJuIGl0ZW1zO1xuICB9KTtcbn0pO1xuIiwibW9kZSI6InN0YW5kYWxvbmUifQ%253D%253D) live in our Playground to see it in action.

## Use cases

The custom annotation toggle button provides users with a way to hide or show all annotations across all pages of a PDF document. This is particularly useful for:

- Reviewing documents with and without annotations

- Presentations where annotations might be distracting

- Comparing original content with annotated versions

- Accessibility scenarios where annotations need to be temporarily hidden

> For documents with many annotations, the toggle operation processes all pages sequentially. Consider implementing batching strategies for optimal performance in large documents.

## Implementation

To create a custom annotation toggle button, follow the steps below.

### Basic setup

First, set up Nutrient Web SDK with your desired configuration:

```javascript

// Initialize the annotation visibility state.
let annotationsHidden = false; // Track the current state.

NutrientViewer.load({
  container: document.getElementById("viewerContainer"),
  document: "path/to/your/document.pdf",
  licenseKey: "your-license-key",
  theme: NutrientViewer.Theme.DARK,
  toolbarItems: [...NutrientViewer.defaultToolbarItems],
}).then(async (instance) => {
  // Custom button implementation goes here.
});

```

### Creating the custom toggle button

Add the custom toggle button to the toolbar:

```javascript

// Define the custom toggle button configuration.
const toggleAnnotationsButton = {
  type: "custom",
  id: "toggle-annotations",
  title: "Toggle Annotations",
  icon: annotationsHidden? "👁️" : "🙈", // Dynamic icon based on state.
  onPress: async () => {
    await toggleAllAnnotations(instance);
  },
};

// Add the button to the toolbar.
instance.setToolbarItems((items) => {
  items.push(toggleAnnotationsButton);
  return items;
});

```

### Complete toggle implementation

Below is the complete implementation with error handling and state management:

```javascript

// Initialize state variable to track annotation visibility.
let annotationsHidden = false;

NutrientViewer.load({
  container: document.getElementById("viewerContainer"),
  document: "path/to/your/document.pdf",
  licenseKey: "your-license-key",
  theme: NutrientViewer.Theme.DARK,
  toolbarItems: [...NutrientViewer.defaultToolbarItems],
}).then(async (instance) => {
  // Function to toggle all annotations across the document.
  const toggleAllAnnotations = async () => {
    try {
      const totalPages = instance.totalPageCount;

      // Process all pages in the document.
      for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) {
        const annotations = await instance.getAnnotations(pageIndex);

        // Update each annotation’s visibility using `Promise.all` for performance.
        const updatePromises = annotations.map(async (annotation) => {
          // Set the `noView` property: invert current state (!annotationsHidden).
          // When `annotationsHidden=false` (visible), set `noView=true` to hide.
          // When `annotationsHidden=true` (hidden), set `noView=false` to show.
          const updatedAnnotation = annotation.set(
            "noView",!annotationsHidden,
          );
          return instance.update(updatedAnnotation);
        });

        // Wait for all updates on current page to complete before proceeding.
        await Promise.all(updatePromises);
      }

      // Toggle the global state.
      annotationsHidden =!annotationsHidden;

      // Update button appearance to reflect new state.
      updateToggleButton();

      console.log(`Annotations ${annotationsHidden? "hidden" : "shown"}`);
    } catch (error) {
      console.error("Error toggling annotations:", error);
    }
  };

  // Function to update button appearance based on current state.
  const updateToggleButton = () => {
    const buttonTitle = annotationsHidden? "Show Annotations"
      : "Hide Annotations";
    const buttonIcon = annotationsHidden? "👁️" : "🙈";

    instance.setToolbarItems((items) => {
      const buttonIndex = items.findIndex(
        (item) => item.id === "toggle-annotations",
      );
      if (buttonIndex!== -1) {
        items[buttonIndex] = {...items[buttonIndex],
          title: buttonTitle,
          icon: buttonIcon,
        };
      }
      return items;
    });
  };

  // Create the initial toggle button configuration.
  const toggleAnnotationsButton = {
    type: "custom",
    id: "toggle-annotations",
    title: "Hide Annotations",
    icon: "🙈",
    onPress: toggleAllAnnotations,
  };

  // Add the button to the toolbar.
  instance.setToolbarItems((items) => {
    items.push(toggleAnnotationsButton);
    return items;
  });
});

```

## Code breakdown

Below is a breakdown of the key parts of the implementation.

### State management

```javascript

let annotationsHidden = false;

```

This variable tracks whether annotations are currently hidden. Starting with `false` means annotations are visible by default.

### Iterating through pages

```javascript

const totalPages = instance.totalPageCount;
for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) {
  const annotations = await instance.getAnnotations(pageIndex);
  // Process annotations.
}

```

The toggle function iterates through all pages in the document to ensure every annotation is affected.

### Updating annotation visibility

```javascript

const updatedAnnotation = annotation.set("noView",!annotationsHidden);
await instance.update(updatedAnnotation);

```

The `noView` property controls annotation visibility:

- `true` — Annotation is hidden

- `false` — Annotation is visible

### Asynchronous processing

```javascript

const updatePromises = annotations.map(async (annotation) => {
  const updatedAnnotation = annotation.set("noView",!annotationsHidden);
  return instance.update(updatedAnnotation);
});

await Promise.all(updatePromises);

```

Using `Promise.all()` ensures all annotations on a page are updated simultaneously for better performance.

## Advanced features

Below are some advanced features you can implement for the annotation toggle functionality.

### Custom icon implementation

Replace emoji icons with SVG or CSS classes for better styling:

```javascript

const toggleAnnotationsButton = {
  type: "custom",
  id: "toggle-annotations",
  title: annotationsHidden? "Show Annotations" : "Hide Annotations",
  className: annotationsHidden? "annotation-hidden-btn"
    : "annotation-visible-btn",
  onPress: toggleAllAnnotations,
};

```

Add the corresponding CSS:

```css.annotation-hidden-btn::before {
  content: "👁️";
  margin-right: 8px;
}.annotation-visible-btn::before {
  content: "🙈";
  margin-right: 8px;
}

```

### Selective annotation types

Hide only specific types of annotations:

```javascript

const toggleSpecificAnnotations = async (
  annotationTypes = ["ink", "highlight"],
) => {
  const totalPages = instance.totalPageCount;

  for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) {
    const annotations = await instance.getAnnotations(pageIndex);

    const filteredAnnotations = annotations.filter((annotation) =>
      annotationTypes.includes(annotation.type),
    );

    const updatePromises = filteredAnnotations.map(async (annotation) => {
      const updatedAnnotation = annotation.set("noView",!annotationsHidden);
      return instance.update(updatedAnnotation);
    });

    await Promise.all(updatePromises);
  }

  annotationsHidden =!annotationsHidden;
};

```

### Animation effects

Add smooth transitions when toggling annotations:

```javascript

const toggleWithAnimation = async () => {
  // Add fade-out effect.
  document.querySelector(".PSPDFKit-Container").style.transition =
    "opacity 0.3s";
  document.querySelector(".PSPDFKit-Container").style.opacity = "0.7";

  await toggleAllAnnotations();

  // Restore opacity.
  setTimeout(() => {
    document.querySelector(".PSPDFKit-Container").style.opacity = "1";
  }, 300);
};

```

### Keyboard shortcut support

Add keyboard shortcuts for the toggle functionality:

```javascript

document.addEventListener("keydown", (event) => {
  // Toggle with Ctrl+H (or Cmd+H on Mac).
  if ((event.ctrlKey || event.metaKey) && event.key === "h") {
    event.preventDefault();
    toggleAllAnnotations();
  }
});

```

## Best practices

Below are some best practices to follow when implementing annotation toggling.

### Error handling

Always wrap annotation operations in try-catch blocks:

```javascript

const toggleAllAnnotations = async () => {
  try {
    // Toggle logic here.
  } catch (error) {
    console.error("Failed to toggle annotations:", error);
    // Show user-friendly error message.
    showErrorMessage("Unable to toggle annotations. Please try again.");
  }
};

```

### Performance optimization

For documents with many annotations, consider batching updates:

```javascript

const BATCH_SIZE = 50;

const toggleAnnotationsInBatches = async () => {
  const totalPages = instance.totalPageCount;
  let allAnnotations = [];

  // Collect all annotations first.
  for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) {
    const pageAnnotations = await instance.getAnnotations(pageIndex);
    allAnnotations = allAnnotations.concat(Array.from(pageAnnotations));
  }

  // Process in batches.
  for (let i = 0; i < allAnnotations.length; i += BATCH_SIZE) {
    const batch = allAnnotations.slice(i, i + BATCH_SIZE);
    const updatePromises = batch.map((annotation) => {
      const updatedAnnotation = annotation.set("noView",!annotationsHidden);
      return instance.update(updatedAnnotation);
    });

    await Promise.all(updatePromises);
  }
};

```

### State persistence

Save the toggle state to `localStorage`:

```javascript

const STORAGE_KEY = "nutrient-annotations-hidden";

// Load initial state.
annotationsHidden = localStorage.getItem(STORAGE_KEY) === "true";

const toggleAllAnnotations = async () => {
  // Toggle logic.

  // Save state.
  localStorage.setItem(STORAGE_KEY, annotationsHidden.toString());
};

```

### Loading indicator

Show progress for large documents:

```javascript

const showLoadingIndicator = () => {
  const loader = document.createElement("div");
  loader.id = "annotation-toggle-loader";
  loader.textContent = "Toggling annotations...";
  loader.style.cssText = `
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: rgba(0,0,0,0.8);
    color: white;
    padding: 20px;
    border-radius: 8px;
    z-index: 10000;
  `;
  document.body.appendChild(loader);
};

const hideLoadingIndicator = () => {
  const loader = document.getElementById("annotation-toggle-loader");
  if (loader) {
    loader.remove();
  }
};

const toggleAllAnnotations = async () => {
  showLoadingIndicator();
  try {
    // Toggle logic here.
  } finally {
    hideLoadingIndicator();
  }
};

```

## Troubleshooting

Use the following troubleshooting tips and solutions when implementing a custom annotation toggle.

### Common issues

**Annotations not hiding**

- Ensure you’re using the correct property name: `noView`.

- Check that annotations are being updated with `instance.update()`.

**Button not appearing**

- Verify the button is being added after the viewer loads.

- Check that `setToolbarItems` is called correctly.

**Performance issues with large documents**

- Implement batching as shown in best practices.

- Consider adding a loading indicator.

- Use `Promise.all()` for concurrent updates.

**State synchronization issues**

- Always update the state variable after successful operations.

- Consider using a more robust state management solution for complex applications.

### Debug helper

Add the following helper function for debugging:

```javascript

const debugAnnotations = async () => {
  const totalPages = instance.totalPageCount;
  console.log(`Document has ${totalPages} pages`);

  for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) {
    const annotations = await instance.getAnnotations(pageIndex);
    console.log(`Page ${pageIndex + 1}: ${annotations.size} annotations`);

    annotations.forEach((annotation, index) => {
      console.log(`  Annotation ${index + 1}:`, {
        type: annotation.type,
        id: annotation.id,
        noView: annotation.noView,
      });
    });
  }
};

// Call in browser console for debugging.
window.debugAnnotations = debugAnnotations;

```

The implementation above provides a robust, user-friendly way to toggle annotation visibility in your web applications using Nutrient Web SDK. The code can be customized further based on specific application requirements and design preferences.

## Next steps

- **Explore related features** — Refer to the [customizing toolbar](https://www.nutrient.io/guides/web/customizing-the-interface/customizing-the-toolbar.md) guide for more toolbar customization options

- **Advanced annotations** — Learn about [annotation types](https://www.nutrient.io/guides/web/annotations/introduction-to-annotations.md) to create targeted toggle functionality

- **Performance optimization** — Review [best practices](https://www.nutrient.io/guides/web/best-practices/performance.md) for handling large documents with many annotations

- **Custom overlay items** — Learn how to create [custom overlay items](https://www.nutrient.io/guides/web/customizing-the-interface/creating-custom-overlay-items.md)
---

## Related pages

- [Embed Web SDK in a dashboard/app shell](/guides/web/viewer/embed-in-dashboard-app-shell.md)
- [JavaScript image viewer library](/guides/web/viewer/images.md)
- [Enhance PDF viewing with linearized downloading](/guides/web/viewer/linearized-downloads.md)
- [Client authentication and session renewal](/guides/web/viewer/client-authentication.md)
- [Office document viewing in JavaScript](/guides/web/viewer/office-documents.md)
- [Mobile responsive JavaScript PDF viewer](/guides/web/viewer/mobile-responsive.md)
- [JavaScript PDF viewer library](/guides/web/viewer.md)
- [Page layout and scroll options in our JavaScript PDF viewer](/guides/web/customizing-the-interface/document-presentation-options.md)
- [JavaScript PDF viewer library](/guides/web/viewer/pdf.md)
- [JavaScript Support in our PDF viewer](/guides/web/features/javascript.md)
- [macOS/Linux](/guides/web/viewer/troubleshooting.md)
- [PDF document streaming in JavaScript](/guides/web/viewer/streaming.md)
- [Enable or disable permissions in our JavaScript viewer](/guides/web/features/document-permissions.md)
- [Zoom options in our JavaScript PDF viewer](/guides/web/viewer/zooming.md)

