Custom Document Outline¶
SciFlow already provides the primitives you need to build a table-of-contents sidebar:
collectDocumentOutline(doc, pmDoc?)– walks either the JSON snapshot or the live ProseMirror document and returns headings + citation lists. Seepackages/editor/start/demo/js/outline.js.OutlinePanel– a ready-made DOM helper used by the demo sidebar.
Use this guide when you want to integrate the same behavior into your own UI.
When to Call collectDocumentOutline¶
| Context | Argument |
|---|---|
| Web component | editor.doc (JSON) and editor.editorView?.state.doc (ProseMirror) |
Core Editor instance |
editor.getDoc() and editor.getView()?.state.doc |
Passing the live ProseMirror document enables accurate position data so outline clicks can set the selection.
Rendering Your Own Panel¶
import { collectDocumentOutline } from '@sciflow/editor-start/demo';
function renderOutline(editor, container) {
const pmDoc = editor.editorView?.state.doc ?? null;
const outline = collectDocumentOutline(editor.doc, pmDoc);
container.innerHTML = '';
outline.headings.forEach((heading) => {
const item = document.createElement('li');
item.textContent = heading.text || 'Untitled section';
item.dataset.level = String(heading.level ?? 1);
if (heading.position != null) {
item.role = 'button';
item.tabIndex = 0;
item.addEventListener('click', () =>
editor.commands?.commands?.setSelection?.(heading.position, { scroll: false }),
);
}
container.appendChild(item);
});
}
Copy the demo implementation
packages/editor/start/demo/js/outline.js contains a full-featured panel with keyboard support, metadata tags, and scroll handling. It’s safe to copy/paste as a starting point.
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
renderOutlineafter callingeditor.configureFeatures(...).
Graceful degradation
If the editor view is not ready yet, collectDocumentOutline still returns heading data with position: null. In that state you can show the outline as read-only and enable click-to-jump later.