Skip to content

Custom Document Outline

Use this guide to wire a table-of-contents sidebar that follows the document structure and supports click-to-jump.

When to Derive the Outline

Context Argument
Web component editor.doc (JSON)
Core Editor instance editor.getDoc()

Position-aware helpers will be exposed through a dedicated API in a future release. Today the JSON snapshot is the supported surface for read-only outlines.

Rendering Your Own Panel

function collectOutline(doc) {
  const headings = [];

  // Derive headings from the JSON snapshot.
  (doc?.content ?? []).forEach((node) => {
    if (node.type === 'heading') {
      headings.push({ text: node.content?.[0]?.text ?? '', level: node.attrs?.level ?? 1, position: null });
    }
  });
  return { headings };
}

function renderOutline(editor, container) {
  const outline = collectOutline(editor.doc);

  container.innerHTML = '';
  outline.headings.forEach((heading) => {
    const item = document.createElement('li');
    item.textContent = heading.text || 'Untitled section';
    item.dataset.level = String(heading.level ?? 1);

    container.appendChild(item);
  });
}

Scrolling Into View

The outline handler can call commands.setSelection(position, { scroll: false }) followed by commands.scrollIntoView() and commands.focus() to keep behavior consistent with the editor’s native navigation.

const runner = editor.commands;
if (runner?.commands?.setSelection) {
  const didSet = runner.commands.setSelection(position, { scroll: false });
  if (didSet && runner.commands.scrollIntoView) {
    runner.commands.scrollIntoView();
  }
  runner.commands.focus?.();
}

Re-render Triggers

  • editor-change – update the outline whenever the document structure changes.
  • Feature toggles – if you enable/disable heading support on the fly, re-run renderOutline after calling editor.configureFeatures(...).

Graceful degradation

With the current public API, collectDocumentOutline returns heading data without live positions. You can show the outline as read-only today and layer in click-to-jump once the position API lands.