# Configure the Editor

> Start with the fields that open the Editor, then add only the options your integration needs.



Set startup options when the Editor mounts. Use runtime methods for changes made after `onReady`.

## Start with a working configuration [#start-with-a-working-configuration]

Continue with the project and sample NDA from the [Editor quickstart](/editor/quickstart):

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

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

const config = {
  selector: '#editor',
  document: '/sample.docx',
  user: {
    name: 'Jordan Lee',
    email: 'jordan@example.com',
  },
  onReady: () => {
    console.info('SuperDoc is ready.');
  },
  onContentError: ({ error }) => {
    console.error('SuperDoc could not read the document.', error);
  },
  onException: ({ error }) => {
    console.error('SuperDoc could not start.', error);
  },
} satisfies Config;

const superdoc = new SuperDoc(config);

window.addEventListener('beforeunload', () => superdoc.destroy());

```

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

```tsx
import { SuperDocEditor, type SuperDocEditorProps } from '@superdoc/react';
import '@superdoc/react/style.css';

const editorProps = {
  document: '/sample.docx',
  user: {
    name: 'Jordan Lee',
    email: 'jordan@example.com',
  },
  onReady: () => {
    console.info('SuperDoc is ready.');
  },
  onContentError: ({ error }) => {
    console.error('SuperDoc could not read the document.', error);
  },
  onException: ({ error }) => {
    console.error('SuperDoc could not start.', error);
  },
} satisfies SuperDocEditorProps;

export function Editor() {
  return <SuperDocEditor {...editorProps} />;
}

```


Both examples reopen `/sample.docx`, assign document activity to Jordan Lee, and report startup errors. `satisfies`
checks field names and values before the Editor receives them.

Notice the boundary:

* Vanilla uses `selector`; the React wrapper creates its own container.
* `document` and `user` describe what opens and who is acting.
* `onReady` marks the first safe moment to enable document actions.
* `onContentError` reports content and import errors. `onException` reports other runtime exceptions.

## Change one startup decision [#change-one-startup-decision]

Set `documentMode` to `suggesting`, then reload the application. New edits are now recorded as tracked changes instead
of changing the document directly.

[Document modes](/editor/document-modes) explains the three modes and lets you run the same edit in each one.

## Find another option [#find-another-option]

Choose a group, then choose a field. The first layer explains what the field changes. Expand **API details** only when
you need the full contract.

### Essentials

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `selector` | `string \| HTMLElement` | — | Required | Choose the element where the Editor mounts. | The selector or element to mount the SuperDoc into. | — |
| `document` | `string \| object \| { lastModified: number; name: string; webkitRelativePath: string; size: number; type: string; arrayBuffer: () => Promise<ArrayBuffer>; bytes: () => Promise<Uint8Array<ArrayBuffer>>; slice: (start: number \| undefined, end: number \| undefined, contentType: string \| undefined) => Blob; stream: () => ReadableStream<Uint8Array<ArrayBuffer>>; text: () => Promise<string>; } \| { size: number; type: string; arrayBuffer: () => Promise<ArrayBuffer>; bytes: () => Promise<Uint8Array<ArrayBuffer>>; slice: (start: number \| undefined, end: number \| undefined, contentType: string \| undefined) => Blob; stream: () => ReadableStream<Uint8Array<ArrayBuffer>>; text: () => Promise<string>; }` | — | Optional | Open a document from a URL, File, Blob, or collaboration source. | The document to load. If a string, it will be treated as a URL. If a File or Blob, it will be used directly. For a v2 collaboration room, pass a structured document carrying `v2Collaboration`. Omitting this field and `documents` mounts a blank DOCX, so the Editor opens a real document rather than an empty surface. The blank document is a supported v2 source; it is seeded before mount and behaves like any other opened DOCX, including export. Setting the v1 `modules.collaboration` field also suppresses that seeding, but it is not a supported v2 path: the runtime fails closed with `collaboration-v1-config-unsupported` and mounts only enough state to report that error. | [Load and save documents](/editor/load-and-save-documents) |
| `user` | `{ color?: string; id?: null \| string; name?: null \| string; email?: null \| string; image?: null \| string; }` | — | Optional | Identify the current user for collaboration and tracked changes. | The current user of this SuperDoc. Typed as `AwarenessUser` (an extension of `User` with the optional `color` field) so consumers can pass an explicit awareness color and have the runtime honor it as an override - `SuperDoc#assignUserColor()` skips its hash-based assignment when `user.color` is already set. | — |
| `onReady` | `(params: { superdoc: SuperDocClass; }) => void` | — | Optional | Enable document actions after the Editor is ready. | Callback when the SuperDoc is ready. Receives a wrapper carrying the live SuperDoc instance. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onContentError` | `(params: { error: unknown; editor: Editor; documentId: string; file: null \| File \| Blob; }) => void` | — | Optional | Handle document import and content errors. | Callback when an editor reports a content error (parse failure, doc import error, etc.). `error` is widened to `unknown` because the document editor side mostly normalizes to `Error` but some emitters (e.g. `insertContentAt`) forward the original caught value. `file` matches `Document.data` (`File \| Blob \| null \| undefined`) since the document can be loaded from any of those shapes. `documentId` is guaranteed at runtime by `#initDocuments`. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onException` | `(params: SuperDocExceptionPayload) => void` | — | Optional | Handle SuperDoc runtime exceptions. | Callback when SuperDoc emits an `exception` event. The payload is a union of three runtime shapes (store init, restore failure, editor lifecycle). Narrow with `'stage' in params` (store init) or `'code' in params` (editor) before reading shape-specific fields. | [Lifecycle and events](/editor/lifecycle-and-events) |

### Document

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `documentMode` | `"editing" \| "viewing" \| "suggesting"` | `'editing'` | Optional | Start in editing, suggesting, or viewing mode. | The mode of the document (default: 'editing'). | [Document modes](/editor/document-modes) |
| `viewing` | `{ comments?: boolean; trackedChanges?: "original" \| "markup" \| "final"; }` | `{ comments: false, trackedChanges: 'original' }` | Optional | Choose what comments and tracked changes viewers see. | What review information is shown when `documentMode` is `viewing`. | [Document modes](/editor/document-modes) |
| `role` | `"editor" \| "viewer" \| "suggester"` | — | Optional | Limit which document modes the current user can enter. | The role of the user in this SuperDoc. | — |
| `allowSelectionInViewMode` | `boolean` | `false` | Optional | Let viewers select text without editing. | When `documentMode` is `'viewing'`, allow the user to make text selections even though editing is disabled. Defaults to `false`. Forwarded to the underlying editor as `options.allowSelectionInViewMode`. | [Document modes](/editor/document-modes) |
| `superdocId` | `string` | — | Optional | Set an ID for this Editor instance. | The ID of the SuperDoc. | — |
| `password` | `string` | — | Optional | Open an encrypted DOCX with its password. | Password for encrypted DOCX files. Forwarded during document load. | — |
| `documents` | `Document[]` | — | Optional | Load documents through the legacy multi-document field. | The documents to load → soon to be deprecated. | — |
| `users` | `User[]` | — | Optional | Provide the people available for mentions. | All users of this SuperDoc (can be used for "@"-mentions). | — |
| `colors` | `string[]` | — | Optional | Provide awareness colors for users. | Colors to use for user awareness. | — |
| `format` | `string` | — | Optional | Declare the input document format. | The format of the document (docx, pdf, html). | — |
| `title` | `string` | — | Optional | Set the Editor title. | The title of the SuperDoc. | — |
| `jsonOverride` | `object` | — | Optional | Replace imported content with JSON. | Provided JSON to override content with. | — |
| `html` | `string` | — | Optional | Initialize the Editor with HTML. | HTML content to initialize the editor with. | — |
| `markdown` | `string` | — | Optional | Initialize the Editor with Markdown. | Markdown content to initialize the editor with. | — |

### Interface

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `ui` | `false \| { toolbar?: false \| true \| { container?: string \| HTMLElement; groups?: string[] \| Record<string, string[]>; excludeItems?: string[]; icons?: Record<string, unknown>; texts?: Record<string, unknown>; hideButtons?: boolean; responsiveToContainer?: boolean; fonts?: ToolbarFontOption[]; customButtons?: readonly ToolbarCustomButton[]; showFormattingMarksButton?: boolean; showTableOfContentsButton?: boolean; }; comments?: false \| true \| CommentsConfig; contextMenu?: false \| true \| ContextMenuConfig; loading?: boolean; search?: false \| true \| FindReplaceConfig; linkPopover?: false \| true \| LinkPopoverConfig; ruler?: false \| true \| { container?: string \| HTMLElement; }; contentControls?: false \| true \| ContentControlsConfig; }` | — | Optional | Choose which built-in interface parts SuperDoc renders. | Which built-in interface SuperDoc renders. Omit it to keep SuperDoc's historical rendering: comments, the context menu, and content-control chrome are on; search, the link popover, and the ruler are opt-in; and the toolbar renders once it has somewhere to mount. That profile is not symmetrical, and omitting this field reproduces it exactly. Pass `false` when the application owns the interface. SuperDoc then renders no controls, chrome, dialogs, or popovers, while the document, the Document API, and `editor.ui` keep working — so a custom UI drives the same commands the built-in one would have. Pass an object to choose per surface. An omitted key keeps that surface's default rather than following its siblings, so `{ comments: false }` disables comments and changes nothing else. | [Who renders the UI?](/editor/who-renders-the-ui) |
| `interaction` | `{ comments?: { readOnly?: boolean; allowResolve?: boolean; }; }` | — | Optional | Set what people can do through Editor interactions. | What the user is permitted to do. Independent of {@link Config.ui}: a `readOnly` policy still applies when the application renders its own comment UI. | [Who renders the UI?](/editor/who-renders-the-ui) |
| `surfaces` | `{ resolver?: null \| (request: SurfaceRequest) => SurfaceResolution \| null \| undefined; dialog?: { closeOnEscape?: boolean; closeOnBackdrop?: boolean; maxWidth?: string \| number; }; floating?: { placement?: SurfaceFloatingPlacement; width?: string \| number; maxWidth?: string \| number; maxHeight?: string \| number; closeOnEscape?: boolean; closeOnOutsidePointerDown?: boolean; autoFocus?: boolean; }; }` | — | Optional | Configure dialogs and floating overlays. | Shared configuration for dialogs and floating overlays, including ones opened through `superdoc.openSurface()`. Stays active under `ui: false`. | [Dialogs and surfaces](/editor/dialogs-and-surfaces) |
| `toolbar` | `string \| HTMLElement` | — | Optional | Choose where the built-in toolbar renders. | Where to render the built-in toolbar. Either an `HTMLElement`, or a selector string in one of the supported forms: an id selector (`#toolbar`), a class selector (`.toolbar`), or a bare element id (`toolbar`). Other CSS selector syntax is not supported — an attribute or descendant selector such as `[data-toolbar]` resolves to nothing and leaves the toolbar unrendered. SuperDoc renders into the resolved element but does not manage its placement, and never includes it in the `contained` layout calculation. Where the application puts it therefore decides the space it needs: a sibling of a 400px `contained` Editor adds its own height alongside it, while a toolbar placed inside that host consumes part of the 400px and can overflow it. Omitting this field (and `modules.toolbar.selector`) renders no toolbar. `modules.toolbar: true` on its own does not render one either — it creates the `superdoc.toolbar` handle without a mount target. See {@link Modules.toolbar}. | [Configure the toolbar](/editor/built-in-ui/configure-the-toolbar) |
| `toolbarGroups` | `string[]` | — | Optional | Choose which toolbar groups appear. | Toolbar groups to show. | [Configure the toolbar](/editor/built-in-ui/configure-the-toolbar) |
| `toolbarIcons` | `object` | — | Optional | Replace icons in the built-in toolbar. | Icons to show in the toolbar. | [Configure the toolbar](/editor/built-in-ui/configure-the-toolbar) |
| `toolbarTexts` | `object` | — | Optional | Replace text in the built-in toolbar. | Texts to override in the toolbar. | [Configure the toolbar](/editor/built-in-ui/configure-the-toolbar) |
| `uiDisplayFallbackFont` | `string` | — | Optional | Set the font used by SuperDoc interface elements. | The font-family to use for all SuperDoc UI surfaces (toolbar, comments UI, dropdowns, tooltips, etc.). This ensures consistent typography across the entire application and helps match your application's design system. The value should be a valid CSS font-family string. Example (system fonts): uiDisplayFallbackFont: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' Example (custom font): uiDisplayFallbackFont: '"Inter", Arial, sans-serif' | [Themes and fonts](/editor/themes-and-fonts) |
| `conversations` | `object[]` | — | Optional | Load conversation data. | The conversations to load. | — |
| `comments` | `{ visible?: boolean; }` | — | Deprecated. Use `viewing.comments` instead. Deprecated. Use viewing.comments. | Legacy comment visibility setting. | Toggle comment visibility when `documentMode` is `viewing`. | [Document modes](/editor/document-modes) |
| `rulers` | `boolean` | — | Optional | Show the measurement ruler. | Whether to show the ruler in the editor. | — |
| `rulerContainer` | `string \| HTMLElement` | — | Deprecated. Use `ui.ruler.container` instead | Choose where the ruler renders. | Element or selector the ruler mounts into. Omit to render it inline above the editor. | — |
| `disableContextMenu` | `boolean` | — | Optional | Disable the built-in slash and context menu. | Whether to disable slash / right-click custom context menu. | — |

### Behavior

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `trackChanges` | `{ visible?: boolean; }` | — | Deprecated. Use `viewing.trackedChanges` instead. Deprecated. Use viewing.trackedChanges. | Legacy tracked-change visibility setting. | Toggle tracked-change visibility when `documentMode` is `viewing`. | [Document modes](/editor/document-modes) |
| `isLocked` | `boolean` | — | Optional | Start the Editor in a locked state. | Whether the SuperDoc is locked. | — |
| `lockedBy` | `{ id?: null \| string; name?: null \| string; email?: null \| string; image?: null \| string; }` | — | Optional | Identify the user who locked the Editor. | The user who locked the SuperDoc. | — |
| `suppressDefaultDocxStyles` | `boolean` | — | Optional | Skip SuperDoc default DOCX styles. | Whether to suppress default styles in docx mode. | — |
| `warnOnUnsupportedContent` | `boolean` | — | Optional | Warn when HTML import drops unsupported elements. | When true and no onUnsupportedContent callback is provided, emits a console.warn with unsupported items. | — |
| `viewOptions` | `{ layout?: "print" \| "web"; }` | — | Optional | Set DOCX-compatible document view options. | Document view options (OOXML ST_View compatible). | — |
| `contained` | `boolean` | `false` | Optional | Keep the Editor inside a fixed-height scrolling container. | Enable contained mode for fixed-height container embedding. SuperDoc supports two layout modes, and the host element's height requirement differs between them: - Natural (default, `false`): the Editor grows to the document's full height and the page scrolls. The host needs no height. Setting one does not constrain the document or enable internal scrolling, because SuperDoc leaves overflow visible in this mode, though application CSS on the host can still clip what is drawn. - Contained (`true`): SuperDoc propagates `height: 100%` through its DOM tree and scrolls the document internally, so multi-page documents stay inside the host. This mode requires the host to have a definite height (for example `height: 400px`); without one there is nothing for the percentage heights to resolve against. A toolbar mounted through `Config.toolbar` or `modules.toolbar.selector` is never part of this calculation. Placed as a sibling of the host, its height adds to the host's: a 400px host with a 40px toolbar occupies 440px in total. Placed inside the host, it consumes part of the 400px instead. | [Responsive layout](/editor/built-in-ui/responsive-layout) |
| `zoom` | `{ initial?: number; mode?: "manual" \| "fit-width"; fitWidth?: SuperDocFitWidthOptions; }` | `{ initial: 100, mode: 'manual' }` | Optional | Set the initial zoom and fit-to-width behavior. | Zoom behavior: the initial zoom level and optional fit-width policy. See `SuperDocZoomConfig`. | [Responsive layout](/editor/built-in-ui/responsive-layout) |
| `measurementUnit` | `"in" \| "cm"` | `'in'` | Optional | Set the ruler and measurement unit. | Starting measurement unit for rulers and measurement fields (Word's "measurement units" preference). Defaults to `'in'` (Word's en-US default). Change it at runtime with `setMeasurementUnit()`. See `SuperDocMeasurementUnit`. | [Responsive layout](/editor/built-in-ui/responsive-layout) |

### Integrations

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `modules` | `{ contentControls?: { chrome?: "default" \| "none"; }; comments?: false \| { permissionResolver?: (params: PermissionResolverParams) => boolean \| undefined; readOnly?: boolean; allowResolve?: boolean; highlightColors?: { internal?: string; external?: string; activeInternal?: string; activeExternal?: string; }; highlightOpacity?: { active?: number; inactive?: number; }; highlightHoverColor?: string; trackChangeHighlightColors?: { insertBorder?: string; insertBackground?: string; deleteBorder?: string; deleteBackground?: string; formatBorder?: string; }; trackChangeActiveHighlightColors?: { insertBorder?: string; insertBackground?: string; deleteBorder?: string; deleteBackground?: string; formatBorder?: string; }; displayMode?: "auto" \| "sidebar" \| "inline"; compactMeasurementSelector?: string; compactBreakpointPx?: number; } & Record<string, unknown>; ai?: { apiKey?: string; endpoint?: string; } & Record<string, unknown>; pdf?: { pdfLib: object; workerSrc?: string; setWorker?: boolean; textLayer?: boolean; outputScale?: number; } & Record<string, unknown>; collaboration?: CollaborationConfig; toolbar?: false \| true \| { selector?: string; excludeItems?: string[]; groups?: Record<string, string[]>; icons?: Record<string, unknown>; texts?: Record<string, string>; fonts?: Array<FontConfig \| ToolbarFontOption>; hideButtons?: boolean; responsiveToContainer?: boolean; customButtons?: Array<Record<string, unknown>>; showFormattingMarksButton?: boolean; showTableOfContentsButton?: boolean; } & Record<string, unknown>; links?: { popoverResolver?: LinkPopoverResolver; } & Record<string, unknown>; contextMenu?: ContextMenuConfig; slashMenu?: object; surfaces?: SurfacesModuleConfig; trackChanges?: TrackChangesModuleConfig; whiteboard?: false \| { enabled?: boolean; }; }` | — | Optional | Enable and configure Editor modules. | Modules to load. | [Track changes](/editor/track-changes) |
| `permissionResolver` | `(params: { permission: string; role: string; isInternal: boolean; defaultDecision: boolean; comment: null \| object; trackedChange: null \| object; currentUser: null \| User; superdoc: null \| SuperDocClass; }) => boolean \| undefined` | — | Optional | Override permission checks for protected content. | Top-level override for permission checks. | — |
| `editorExtensions` | `object[]` | — | Ignored by superdoc@2. Use extensions. | Legacy v1 extension field. SuperDoc v2 ignores it. | Legacy v1 ProseMirror extensions. `editorExtensions` is a v1/ProseMirror concept and is IGNORED by `superdoc@2`: these objects are never loaded into the v2 runtime. Passing `editorExtensions` records a clear console diagnostic at construction. For v2, use {@link Config.extensions} with `defineSuperDocExtension`; the two are not interchangeable. | — |
| `extensions` | `SuperDocExtension<Record<string, unknown>>[]` | — | Optional | Add extensions created with `defineSuperDocExtension`. | v2 SuperDoc extensions, created with `defineSuperDocExtension`. `superdoc@2` IS the v2 editor, so these activate unconditionally — there is no `editorVersion` / `editorIntegration` selector. Each extension owns isolated storage, named events, commands, anchors, and render-only decorations, and mutates the document exclusively through the guarded Document API (`ctx.doc.*`). This is the v2 replacement for the v1/ProseMirror `editorExtensions` path; the two are not interchangeable. Extension arrays are mount-time config: changing the array reference requires a remount to take effect. | — |
| `handleImageUpload` | `(file: { lastModified: number; name: string; webkitRelativePath: string; size: number; type: string; arrayBuffer: () => Promise<ArrayBuffer>; bytes: () => Promise<Uint8Array<ArrayBuffer>>; slice: (start: number \| undefined, end: number \| undefined, contentType: string \| undefined) => Blob; stream: () => ReadableStream<Uint8Array<ArrayBuffer>>; text: () => Promise<string>; }) => Promise<string>` | — | Optional | Store images inserted into the document. | The function to handle image uploads. | — |
| `cspNonce` | `string` | — | Optional | Apply a Content Security Policy nonce to injected styles. | Content Security Policy nonce for dynamically injected styles. | [Secure integration](/editor/secure-integration) |
| `licenseKey` | `string` | — | Optional | Identify the licensed organization. | License key for organization identification. | [License](/editor/license) |
| `telemetry` | `{ enabled: boolean; endpoint?: string; metadata?: Record<string, unknown>; licenseKey?: string; }` | `{ enabled: true }` | Optional | Enable or disable telemetry. | Telemetry configuration. | [Telemetry](/editor/telemetry) |
| `proofing` | `ProofingConfig` | — | Optional | Configure spelling and grammar checks. | Proofing / spellcheck configuration. | [Add proofing](/editor/platform/proofing) |
| `fonts` | `{ bundled?: false \| true \| string[] \| Record<string, unknown> \| "baseline" \| "full"; families?: FontFamilyConfig[]; assetBaseUrl?: string; resolveAssetUrl?: (context: import("@superdoc/font-system").FontAssetUrlContext) => string; assetUrl?: string \| (context: import("@superdoc/font-system").FontAssetUrlContext) => string; }` | — | Optional | Configure document fonts and font asset loading. | Font system configuration. The reviewed fallback pack ships in the optional `@superdoc-dev/fonts` package: pass `superdocFonts` (bundler) or the `SuperDocFonts` global from its `superdoc-fonts.min.js` browser build (CDN). To self-host, set `fonts.assetBaseUrl` (e.g. `/fonts/` or a CDN URL) or `fonts.resolveAssetUrl` for signed/versioned hosting. SuperDoc core ships no fonts; with none configured the toolbar shows the baseline and documents render with system fonts. | [Themes and fonts](/editor/themes-and-fonts) |
| `workerUrls` | `{ document?: string \| URL; collaboration?: string \| URL; reviewIndex?: string \| URL; }` | — | Optional | Load browser workers from same-origin URLs. | Optional same-origin URLs for v2's browser worker assets. Configure these when the application and SuperDoc bundle are served from different origins. Omitted entries keep SuperDoc's bundled worker URLs. | [Secure integration](/editor/secure-integration) |

### Lifecycle

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `onEditorBeforeCreate` | `(params: { editor: Editor; }) => void` | — | Optional | Run code before an editor is created. | Callback before an editor is created. Receives a wrapper carrying the editor. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onEditorCreate` | `(params: { editor: Editor; }) => void` | — | Optional | Run code after an editor is created. | Callback after an editor is created. Receives a wrapper carrying the editor. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onSourceComplete` | `() => void` | — | Optional | Run code when the document is ready for diff capture. | Callback when the v2 document source reaches source-complete posture and diff.capture is safe to call. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onSourceSignalsComplete` | `() => void` | — | Optional | Run code after source signals finish building. | Callback when v2 source signals finish building (fires after onSourceComplete; diff.capture is synchronously safe). | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onTransaction` | `(params: { editor: Editor; sourceEditor: Editor; transaction: EditorTransactionLike; duration?: number; surface: "body" \| "header" \| "footer"; headerId?: null \| string; sectionType?: null \| string; }) => void` | — | Optional | Observe each editor transaction. | Callback when a transaction is made. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onEditorDestroy` | `() => void` | — | Optional | Run cleanup after an editor is destroyed. | Callback after an editor is destroyed. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onCommentsUpdate` | `(params: { type: string; comment?: Comment; changes?: { key: string; commentId: string; fileId?: string \| null; }[]; pendingSelection?: null \| SelectionInfo; }) => void` | — | Optional | React when comments change. | Callback when comments are updated. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onContentControlActiveChange` | `(params: { active: null \| SdtRef; previous: null \| SdtRef; activePath: SdtRef[]; source: "keyboard" \| "pointer"; }) => void` | — | Optional | React when the active content control changes. | Callback when active content control changes. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onContentControlClick` | `(params: { target: SdtRef; source: "pointer"; }) => void` | — | Optional | React when a person selects a content control. | Callback when user clicks inside a content control. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onAwarenessUpdate` | `(params: { states: AwarenessState[]; added: number[]; removed: number[]; superdoc: SuperDocClass; }) => void` | — | Optional | React when collaboration awareness changes. | Callback when awareness is updated. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onLocked` | `(params: { isLocked: boolean; lockedBy: null \| User; }) => void` | — | Optional | React when the Editor locks or unlocks. | Callback when the SuperDoc is locked or unlocked. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onPdfDocumentReady` | `() => void` | — | Optional | Run code when a PDF document is ready. | Callback when the PDF document is ready. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onSidebarToggle` | `(isOpened: boolean) => void` | — | Optional | React when the sidebar opens or closes. | Callback when the sidebar is toggled. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onCollaborationReady` | `(params: { editor: Editor; }) => void` | — | Optional | Enable shared-document actions when collaboration is ready. | Callback when collaboration is ready. Receives a wrapper carrying the editor. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onEditorUpdate` | `(params: { editor?: Editor; sourceEditor?: Editor; surface: "body" \| "header" \| "footer"; headerId: null \| string; sectionType: null \| string; }) => void` | — | Optional | React after document content changes. | Callback when document is updated. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onCommentsListChange` | `(params: { isRendered: boolean; }) => void` | — | Optional | React when the comments list is rendered. | Callback when the comments list is rendered. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onPaginationUpdate` | `(params: { totalPages: number; superdoc: SuperDocClass; }) => void` | — | Optional | Read the page count after a layout update. | Callback when pagination layout updates (fires after each layout pass with the current page count). | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onListDefinitionsChange` | `(params: ListDefinitionsPayload) => void` | — | Optional | React when list definitions change. | Callback when the list definitions change. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onZoomChange` | `(params: { zoom: number; mode: "manual" \| "fit-width"; }) => void` | — | Optional | React when the zoom level changes. | Callback when the zoom level changes. Fires for every zoom source: `setZoom()`, the toolbar zoom control, and fit-width adjustments. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onViewportChange` | `(params: { availableWidth: number; documentWidth: number; fitZoom: number; }) => void` | — | Optional | React when fit-to-width measurements change. | Callback when the implied fit changes (rounded fit zoom or base page width); pixel-level width jitter does not fire it, and `getViewportMetrics()` always reads latest. Registered before the first emit. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onUnsupportedContent` | `(items: { tagName: string; outerHTML: string; count: number; }[]) => void \| null` | — | Optional | Handle HTML elements dropped during import. | Callback invoked with unsupported HTML elements dropped during import. When provided, console.warn is NOT emitted. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onFontsResolved` | `(payload: { report?: FontResolutionRecord[]; missingFonts?: string[]; documentFonts?: string[]; documentFontOptions?: DocumentFontOption[]; }) => void` | — | Optional | Receive the early font-resolution report. | Callback fired after the editor reports `fonts-resolved`. The payload contains `documentFonts` and `unsupportedFonts` arrays so hosts can fall back, warn, or block printing on unsupported faces. LEGACY/EARLY: this fires once before fonts load and is not substitution-aware (`unsupportedFonts` over-reports families that render via a bundled substitute). For the authoritative, load-settled picture use {@link onFontsChanged}. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onPageCountKnown` | `(payload: { pageCount: number; generation: number; }) => void` | — | Optional | Read the page count before paint. | Painter plan P7 §1 (@experimental): fires when the paginated page count changes, at layout-end — before resolve or paint, so page counters and minimaps can trust the number as soon as it is knowable. The payload's `generation` identifies the announcing layout pass (informational; the event is keyed on page-count changes, not generations). v2 vertical pagination only; semantic "web layout" surfaces never fire it. | [Lifecycle and events](/editor/lifecycle-and-events) |
| `onFontsChanged` | `(payload: { source?: string; loadSummary?: null \| FontLoadSummary; report?: FontResolutionRecord[]; missingFonts?: string[]; documentFonts?: string[]; documentFontOptions?: DocumentFontOption[]; }) => void` | — | Optional | Receive final font loading and substitution results. | Callback fired with the authoritative substitution + load-aware font report: once after the load-before-measure gate settles (`source: 'initial'`), again when a face arrives after a timed-out first paint (`'late-load'`). Each payload carries the full per-font `resolutions`, the genuinely `missingFonts`, and a `loadSummary`. Also available to pull on demand via `superdoc.fonts.getReport()`. | [Lifecycle and events](/editor/lifecycle-and-events) |

### Advanced

| Field | Type | Default | Status | Summary | API details | Guide |
| --- | --- | --- | --- | --- | --- | --- |
| `isDev` | `boolean` | — | Optional | Enable development behavior for this instance. | Whether the SuperDoc is in development mode. | — |
| `disablePiniaDevtools` | `boolean` | — | Optional | Disable Pinia and Vue devtools for this instance. | Disable Pinia/Vue devtools plugin setup for this SuperDoc instance (useful in non-Vue hosts). | — |
| `layoutEngineOptions` | `{ flowMode?: "paginated" \| "semantic"; trackedChanges?: object; virtualization?: { enabled?: boolean; window?: number; overscan?: number; }; showBookmarks?: boolean; showFormattingMarks?: boolean; paintHud?: boolean; }` | — | Optional | Override page layout and rendering behavior. | Layout engine overrides passed through to DocumentRendererRuntime (page size, margins, virtualization, zoom, debug label, etc.). | [Performance](/editor/performance-and-large-documents) |
| `experimental` | `{ unifiedHistory?: boolean; v2Host?: boolean; v2WebSurface?: "dense-control" \| "retained-dom"; deferDerivedInvalidations?: boolean; }` | — | Optional | Configure experimental Editor features. | Advanced DocumentRendererRuntime feature toggles. `unifiedHistory` is enabled by default; set it to `false` to force legacy active-surface undo routing. `v2Host` enables the experimental mode-aware v2 DOCX shell path. | — |
| `isInternal` | `boolean` | — | Optional | Mark this instance as internal. | Whether the SuperDoc is internal. | — |
| `isDebug` | `boolean` | — | Optional | Enable debug behavior. | Whether to enable debug mode. | — |
| `workerStartupTimeoutMs` | `number` | `30000` | Optional | Set how long the document worker may take to start. | Budget for the document worker to start up, in milliseconds (default: 30000). Measured from worker spawn, so it covers script download, parsing, evaluation, and the worker's first response to SuperDoc. Raise it when a large worker chunk is served over a slow connection or a cold dev-server cache; lower it to fail faster. Worker load errors are reported immediately and do not wait for this budget. Must be a finite positive number no greater than 2147483647, the platform timer ceiling above which a delay would fire immediately. | [Performance](/editor/performance-and-large-documents) |
| `useLayoutEngine` | `boolean` | — | Optional | Keep compatibility with configurations that set this field. | Compatibility toggle retained for existing configurations. V2 always uses the OOXML kernel; `viewOptions.layout` selects the mounted renderer. | — |


## Change a running Editor [#change-a-running-editor]

After `onReady`, prefer a runtime method when one exists. In React, access these methods through
`editorRef.current?.getInstance()`.

| Change           | Runtime method                 |
| ---------------- | ------------------------------ |
| Document         | `replaceFile()`                |
| Document mode    | `setDocumentMode()`            |
| Zoom             | `setZoom()` or `setZoomMode()` |
| Measurement unit | `setMeasurementUnit()`         |
| Bookmarks        | `setShowBookmarks()`           |
| Formatting marks | `setShowFormattingMarks()`     |

To change `extensions` or `workerUrls`, create a new Editor. Vanilla must destroy the current `SuperDoc` before creating
its replacement. In React, remount `SuperDocEditor` by changing its `key`; the wrapper destroys the old instance.
Recreating the Editor can reset selection and temporary interface state.

## Choose the next decision [#choose-the-next-decision]

* [Load and save documents](/editor/load-and-save-documents) to connect the Editor to your backend storage.
* [Who renders the UI?](/editor/who-renders-the-ui) to choose between built-in, hybrid, and custom interface ownership.
