---
title: "Replace the main toolbar with UI slots | Nutrient Web SDK"
canonical_url: "https://www.nutrient.io/guides/web/user-interface/ui-customization/replace-main-toolbar-with-ui-slots/"
md_url: "https://www.nutrient.io/guides/web/user-interface/ui-customization/replace-main-toolbar-with-ui-slots.md"
last_updated: "2026-08-12T00:00:00.000Z"
description: "Rebuild the default primary toolbar using ui.tools.main, the minimal UI preset, ViewState and Instance APIs, annotation presets, and optional built-in sidebar restoration."
---

# Replace the main toolbar with UI slots

When you need full control over the primary toolbar (not just reordering or hiding items on the [default toolbar](https://www.nutrient.io/guides/web/customizing-the-interface/customizing-the-toolbar.md)), use the UI customization [main tools slot](https://www.nutrient.io/guides/web/user-interface/ui-customization/supported-slots.md) together with the `minimal` preset as your baseline. That hides Nutrient’s built-in chrome so your DOM strip can sit in the main tools region while you drive behavior through public APIs.

This guide ties together patterns that are documented across several articles so you can reproduce built-in behavior consistently.

Prefer tuning the built-in toolbar first ([remove](https://www.nutrient.io/guides/web/customizing-the-interface/customizing-the-toolbar.md), [rearrange](https://www.nutrient.io/guides/web/user-interface/main-toolbar/rearrange.md), [custom tools](https://www.nutrient.io/guides/web/user-interface/main-toolbar/create-a-new-tool.md)) if that meets your needs — less code and fewer APIs to wire.

## 1. Start with minimal UI and define your main toolbar

The [minimal UI preset](https://www.nutrient.io/api/web/modules/UI.html#Configuration) applies a baseline configuration that hides almost all UI, including the default `main` and `contextual` tool strips. You then override only the slots you need; merges are deep, so nested keys combine with the preset.

Typical pattern:

```ts

NutrientViewer.load({
  //...
  ui: {
    preset: "minimal",
    tools: {
      main: (getInstance, id) => ({
        render: () => {
          const root = document.createElement("div");
          // Build your toolbar DOM; call `getInstance()` inside handlers when you need the viewer.
          return root;
        },
      }),
      contextual: (getInstance, id) => ({ render: () => null }),
    },
  },
});

```

Use [`instance.setUI()`](https://www.nutrient.io/guides/web/user-interface/ui-customization/set-ui/) the same way if you attach the strip after load.

## 2. Restore the built-in sidebar shell (thumbnails, outline, …)

The minimal preset also hides [`sidebar.container`](https://www.nutrient.io/guides/web/user-interface/ui-customization/supported-slots/) — the layout shell that hosts the built-in thumbnails, outline, annotations list, and bookmarks panels. If you only set [`sidebarMode`](https://www.nutrient.io/api/web/NutrientViewer.ViewState.html#sidebarMode) on the view state, nothing visible opens until that container exists again.

Override the preset entry so the default sidebar UI comes back:

```ts

ui: {
  preset: "minimal",
  tools: {
    /*... */
  },
  sidebar: {
    container: undefined,
  },
},

```

Setting `container` to `undefined` clears the preset’s hidden slot for that key after merge, which restores the stock sidebar chrome. You still control which panel is open via `sidebarMode` (strings such as `"THUMBNAILS"`, `"DOCUMENT_OUTLINE"`, `"ANNOTATIONS"`, `"BOOKMARKS"`, or `null` to close). See [hide or show the sidebar](https://www.nutrient.io/guides/web/customizing-the-interface/controlling-the-sidebar-via-api.md) and [custom sidebars](https://www.nutrient.io/guides/web/user-interface/ui-customization/custom-sidebars.md).

## 3. Map toolbar actions to APIs

There is no single internal “toolbar item ID → one method” registry in public documentation. In practice, you combine [`Instance`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html), [`ViewState`](https://www.nutrient.io/guides/web/customizing-the-interface/viewstate/), and (for annotation tools) interaction mode + [annotation preset ID](https://www.nutrient.io/guides/web/user-interface/annotations/replicating-built-in-tool-variants.md) the same way the default toolbar does.

| Goal                                                  | Typical approach (from a slot, use your `getInstance` argument)                                                                                                                     |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Sidebar panels                                        | `getInstance()?.setViewState(vs => vs.set("sidebarMode", modeOrNull))`                                                                                                              |
| Page navigation                                       | `getInstance()?.setViewState(vs => vs.goToPreviousPage())` / `goToNextPage()`                                                                                                       |
| Zoom                                                  | `getInstance()?.setViewState(vs => vs.zoomIn())` / `zoomOut()`, or set `"zoom"` to `"FIT_TO_VIEWPORT"` / `"FIT_TO_WIDTH"`                                                           |
| Pan/selection/marquee zoom                            | Set `"interactionMode"` on view state to the same string values as [`InteractionMode`](https://www.nutrient.io/api/web/NutrientViewer.InteractionMode.html) (for example, `"PAN"`, `"MULTI_ANNOTATIONS_SELECTION"`, `"MARQUEE_ZOOM"`)  |
| Annotation tools (arrow, highlighter, dashed rect, …) | On the instance from `getInstance()`, set `interactionMode` and `setCurrentAnnotationPreset(id)` together — see [replicate built-in annotation tool variants](https://www.nutrient.io/guides/web/user-interface/annotations/replicating-built-in-tool-variants.md) |
| Search/document editor/crop                           | Set `"interactionMode"` to `"SEARCH"`, `"DOCUMENT_EDITOR"`, `"DOCUMENT_CROP"` as needed                                                                                             |
| Print/export                                          | [`getInstance()?.print()`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#print), [`getInstance()?.exportPDF()`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#exportPDF) (subject to license/permissions)                                                             |
| Undo/redo                                             | [`getInstance()?.history`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#history)                                                                                                                                                 |

Strings are often enough in plain JavaScript; TypeScript projects can use enums from the SDK where imported.

### Reflecting the active tool in your UI

[`viewState.change`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#~ViewStateChangeEvent) carries view state updates (including `interactionMode`). `currentAnnotationPreset` isn’t part of `ViewState` — refresh highlighted tool state after calling `setCurrentAnnotationPreset`, not only when `viewState.change` fires.

## 4. Related guides

- [UI customization introduction](https://www.nutrient.io/guides/web/user-interface/ui-customization/introduction.md) — Slots, lifecycle, `render` purity

- [Instance nullability and interactive slots](https://www.nutrient.io/guides/web/user-interface/ui-customization/introduction.md#instance-nullability-and-interactive-slots) — Use the `getInstance()` accessor from slot callbacks (call it when you need the instance; don’t cache `getInstance()` once at factory setup for later clicks)

- [Supported slots](https://www.nutrient.io/guides/web/user-interface/ui-customization/supported-slots.md) — Full slot list

- [Set UI configuration](https://www.nutrient.io/guides/web/user-interface/ui-customization/set-ui.md) — Update slots after load

- [View state](https://www.nutrient.io/guides/web/customizing-the-interface/viewstate.md) — Snapshot model for zoom, sidebar, layout

- [Replicate built-in annotation tool variants](https://www.nutrient.io/guides/web/user-interface/annotations/replicating-built-in-tool-variants.md) — Preset ↔ mode matrix
---

## Related pages

- [Building a comment thread UI with the customization API](/guides/web/user-interface/ui-customization/comment-thread-example.md)
- [Custom sidebars](/guides/web/user-interface/ui-customization/custom-sidebars.md)
- [Building a custom document editor sidebar with the customization API](/guides/web/user-interface/ui-customization/document-editor-sidebar-example.md)
- [Slot customization examples](/guides/web/user-interface/ui-customization/examples.md)
- [Building headless document UIs](/guides/web/user-interface/ui-customization/headless-ui.md)
- [Customizing the Nutrient Web SDK UI](/guides/web/user-interface/ui-customization/introduction.md)
- [Set UI customization configuration](/guides/web/user-interface/ui-customization/set-ui.md)
- [Supported slots for UI customization](/guides/web/user-interface/ui-customization/supported-slots.md)

