Integration

Open dialogs and floating surfaces

Render application UI in SuperDoc-managed dialog and floating layers with explicit lifecycle outcomes.

Surfaces place application UI above the document without coupling it to Editor internals. Use a dialog for modal decisions and a floating surface for a non-modal tool or inspector.

import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

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

export const confirmInEditor = async (message: string): Promise<boolean> => {
  const handle = superdoc.openSurface<{ confirmed: true }>({
    mode: 'dialog',
    title: 'Confirm action',
    render: ({ container, close, resolve }) => {
      const text = document.createElement('p');
      text.textContent = message;
      const cancel = document.createElement('button');
      cancel.type = 'button';
      cancel.textContent = 'Cancel';
      const confirm = document.createElement('button');
      confirm.type = 'button';
      confirm.textContent = 'Confirm';
      cancel.addEventListener('click', () => close('cancel'));
      confirm.addEventListener('click', () => resolve({ confirmed: true }));
      container.append(text, cancel, confirm);
    },
  });

  const outcome = await handle.result;
  return outcome.status === 'submitted' && outcome.data?.confirmed === true;
};

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

The render() callback receives an empty container plus resolve() and close() controls. Mount DOM, React, Vue, or another framework into that container and return cleanup for any framework root or listener that outlives the nodes themselves.

handle.result resolves for normal lifecycle outcomes. Check status before reading data: a surface can be submitted, closed, replaced by another surface in the same slot, or destroyed with the Editor. There is one active slot per mode.

Give every surface a visible title, ariaLabel, or ariaLabelledBy. Decide whether Escape, backdrop clicks, and outside pointer events should close it. These defaults affect interaction, not authorization or transaction safety.

Configure modules.surfaces only for shared defaults, intent resolution, or built-in surfaces such as find/replace and password prompts. Direct openSurface() calls do not require a resolver.