# Configure the built-in toolbar

> Show only the controls your workflow needs and keep them reachable as the Editor narrows.



Compare three ways to shape the built-in toolbar, then add a focused version to the `/sample.docx` project from the
[Quickstart](/editor/quickstart).

## Try the toolbar configurations [#try-the-toolbar-configurations]

Expand the Editor and switch between the three configurations:

1. **Focus** shows only the controls named in `items`, placed in the left, center, and right regions.
2. **Remove** starts with the default toolbar and removes Bold and Italic with `excludeItems`.
3. **Add** keeps the focused toolbar and appends an **Add note** action with `customItems`. Place the caret in the
   document, then run it to insert `Review note: `.

> **Interactive editor: Shape the built-in toolbar**
>
> Sample: [open the fixture](/fixtures/formatting-sample.docx).
>
> Preset: `toolbar`.
>
> Toolbar configurations available in the interactive Editor:
>
> - **Focus — `ui.toolbar.items`:** show only undo, redo, bold, italic, underline, link, document-mode, zoom across the left, center, and right regions.
> - **Remove — `ui.toolbar.excludeItems`:** start with the default toolbar and remove bold and italic.
> - **Add — `ui.toolbar.customItems`:** add an **Add note** action to the focused toolbar. Place the caret in the document and run it to insert `Review note: `.
>
> Changing a toolbar configuration recreates the Editor from its current DOCX. Document edits and document mode remain; transient selection and toolbar state reset.
>
> Local DOCX selection: disabled.


Switching configurations recreates the Editor from its current DOCX state because toolbar composition is a startup
option. Edits and document mode remain; the current selection resets.

## Build the focused toolbar [#build-the-focused-toolbar]

Vanilla needs separate toolbar and Editor mounts:

```html
<div id="toolbar"></div>
<div id="editor"></div>

<script type="module" src="/src/main.ts"></script>

```

React's `SuperDocEditor` creates the toolbar mount for you. Add the focused configuration to the Editor setup:

**Vanilla — `src/main.ts`**

```ts
import { SuperDoc, type ToolbarConfig } from 'superdoc';
import 'superdoc/style.css';

const toolbar = {
  container: '#toolbar',
  items: {
    left: ['undo', 'redo'],
    center: ['bold', 'italic', 'underline', 'link', 'image', 'table', 'table-actions'],
    right: ['document-mode', 'zoom'],
  },
  responsiveTo: 'container',
} satisfies ToolbarConfig;

function withImageMimeType(file: File): Blob {
  const type = file.type.toLowerCase();
  if (type === 'image/png' || type === 'image/jpeg' || type === 'image/jpg') return file;
  if (type) throw new Error('Choose a PNG or JPEG image.');
  if (/\.png$/i.test(file.name)) return file.slice(0, file.size, 'image/png');
  if (/\.jpe?g$/i.test(file.name)) return file.slice(0, file.size, 'image/jpeg');
  throw new Error('Choose a PNG or JPEG image.');
}

function handleImageUpload(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result));
    reader.onerror = () => reject(reader.error ?? new Error('Could not read image.'));
    reader.readAsDataURL(withImageMimeType(file));
  });
}

const superdoc = new SuperDoc({
  selector: '#editor',
  document: '/sample.docx',
  handleImageUpload,
  ui: { toolbar },
});

```

**React — `src/App.tsx`**

```tsx
import { useRef, useState } from 'react';
import { SuperDocEditor, type SuperDocRef, type ToolbarConfig } from '@superdoc/react';
import '@superdoc/react/style.css';

const toolbar = {
  items: {
    left: ['undo', 'redo'],
    center: ['bold', 'italic', 'underline', 'link', 'image', 'table', 'table-actions'],
    right: ['document-mode', 'zoom'],
  },
  responsiveTo: 'container',
} satisfies ToolbarConfig;

function withImageMimeType(file: File): Blob {
  const type = file.type.toLowerCase();
  if (type === 'image/png' || type === 'image/jpeg' || type === 'image/jpg') return file;
  if (type) throw new Error('Choose a PNG or JPEG image.');
  if (/\.png$/i.test(file.name)) return file.slice(0, file.size, 'image/png');
  if (/\.jpe?g$/i.test(file.name)) return file.slice(0, file.size, 'image/jpeg');
  throw new Error('Choose a PNG or JPEG image.');
}

function handleImageUpload(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result));
    reader.onerror = () => reject(reader.error ?? new Error('Could not read image.'));
    reader.readAsDataURL(withImageMimeType(file));
  });
}

export default function App() {
  const editorRef = useRef<SuperDocRef>(null);
  const exportingRef = useRef(false);
  const [ready, setReady] = useState(false);
  const [exporting, setExporting] = useState(false);

  async function exportDocument() {
    if (exportingRef.current) return;
    exportingRef.current = true;
    setExporting(true);
    try {
      await editorRef.current?.getInstance()?.export({ exportType: ['docx'], exportedName: 'sample-edited' });
    } catch (error) {
      console.error('SuperDoc could not export the document.', error);
    } finally {
      exportingRef.current = false;
      setExporting(false);
    }
  }

  return (
    <main>
      <button disabled={!ready || exporting} onClick={() => void exportDocument()} type='button'>
        Export DOCX
      </button>
      <SuperDocEditor
        document='/sample.docx'
        handleImageUpload={handleImageUpload}
        onContentError={({ error }) => console.error('SuperDoc could not open the document.', error)}
        onException={({ error }) => console.error('SuperDoc could not open the document.', error)}
        onReady={() => setReady(true)}
        ref={editorRef}
        ui={{ toolbar }}
      />
    </main>
  );
}

```


Reload the application. The toolbar should contain eleven controls across the three regions. Select text and choose
**Bold** to confirm that the control follows the current selection.

**Table** inserts a table at the current selection. **Table actions** becomes available when the selection is inside a table;
use it to add or remove rows and columns, merge or split cells, change borders, or remove the table.

Select **Image** to choose a local file. SuperDoc invokes `handleImageUpload`. These examples return data URLs, so the
workflow needs no backend or temporary object URL. `withImageMimeType` keeps extension-accepted PNG and JPEG files
insertable when the browser leaves `file.type` empty. SuperDoc immediately fetches object or HTTP URLs returned by a
handler and embeds the image in the DOCX. The URL only needs to remain readable until that fetch completes. Same-origin
URLs need no extra server configuration. For another origin, return a public or presigned URL that the browser can read
without cross-origin cookies or custom authorization headers. Configure cross-origin requests (CORS) to allow the
application's origin.

For reusable document fields rather than toolbar actions, [Configure content controls](/editor/built-in-ui/content-controls).

## Configure the toolbar [#configure-the-toolbar]

Choose a group, then choose a field. Each entry shows its type, default, and a configuration fragment you can copy.
Leave `container` unset to let React's `SuperDocEditor` create the toolbar mount. Set it in either Vanilla or React when
your application provides an external toolbar container.

### Controls

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `items` | `{ left?: readonly ToolbarItemId[]; right?: readonly ToolbarItemId[]; center?: readonly ToolbarItemId[]; }` | — | Optional | Show only these built-in controls, grouped by toolbar region. | Built-in controls to render by region. Controls keep their built-in order. Omit to use the default toolbar. | — |
| `excludeItems` | `readonly (ToolbarItemId \| ToolbarLegacyItemId \| (string & {}))[]` | — | Optional | Remove built-in or custom controls from the toolbar. | Controls to remove. Also accepts the id of a custom item. | — |
| `customItems` | `readonly ToolbarCustomItem[]` | — | Optional | Add application buttons, dropdowns, or separators. | Application-defined controls and separators to add. | — |
| `includeItems` | `readonly ToolbarOptionalItemId[]` | — | Optional | Add optional built-in controls to the toolbar. | Additional opt-in controls. With `items`, each uses its built-in region unless already listed. | — |

### Layout

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `container` | `string \| HTMLElement` | — | Optional | Choose an app-owned element that receives the toolbar. Leave this unset to let React's SuperDocEditor create its internal mount. | Where to render the toolbar: an element, an id selector (`#toolbar`), a class selector (`.toolbar`), or a bare element id. Other CSS selector syntax resolves to nothing. | — |
| `overflow` | `"menu" \| "visible"` | `'menu'` | Optional | Move controls that do not fit into a menu, or keep them visible. | How the toolbar handles controls that no longer fit (default: `'menu'`). | — |
| `responsiveTo` | `"container" \| "viewport"` | `'viewport'` | Optional | Measure available width from the toolbar container or the viewport. | Width source used to lay out the toolbar (default: `'viewport'`). | — |

### Appearance

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `icons` | `Readonly<Partial<Record<ToolbarIconId, string>> & Record<string, unknown>>` | — | Optional | Replace built-in toolbar icons with trusted inline SVG markup. | Trusted inline SVG overrides keyed by public icon id. | — |
| `strings` | `Readonly<Partial<Record<ToolbarStringId, string>>>` | — | Optional | Replace built-in toolbar labels and tooltips. | Text overrides keyed by public string id. | — |
| `fontOptions` | `readonly ToolbarFontFamilyOption[]` | — | Optional | Choose the font families listed in the toolbar dropdown. | Options shown in the font-family dropdown. Register loadable fonts through `fonts.families`. | — |


Use `items` for a focused allowlist, `excludeItems` to remove a few controls from the default toolbar, and `customItems`
to add application actions. Controls listed in `items` keep their built-in order within each region.

For a custom item, use `command` when it can run one built-in action directly. Use `onSelect` for registered commands or
workflows that need more input; its context includes `execute` and `executeAsync`.

Keep `satisfies ToolbarConfig` from the examples. It checks control IDs, icon and string slots, font options, and custom
item shapes without widening the object. Prefer one composition strategy instead of combining a long `items` allowlist
with a long `excludeItems` list.

## Check the narrow layout [#check-the-narrow-layout]

`responsiveTo: 'container'` measures the toolbar mount instead of the browser window. With the default
`overflow: 'menu'`, controls that no longer fit move into the overflow menu. SuperDoc adds its trigger when needed; do
not list it in `items`.

Resize the Editor to your narrowest supported width. Every required control should remain reachable, and the toolbar
should not add horizontal page overflow. See [Layout](/editor/built-in-ui/responsive-layout) for document scaling,
contained scrolling, and fullscreen behavior.

The toolbar reads state from the Editor. Controls become active or disabled as the selection, document mode, and current
content change.

## Continue to comments [#continue-to-comments]

[Add the built-in comments UI](/editor/built-in-ui/comments) and preserve comment threads in the exported DOCX.
