The Obsidian Editor API doesn’t expose scroll-position control precise enough for this. For most editing contexts, the cleaner solution is to drop down to CodeMirror 6’s EditorView via editor.cm:
import { EditorView } from '@codemirror/view';
editor.cm.dispatch({
effects: EditorView.scrollIntoView(
editor.cm.state.selection.main.head,
{ y: 'center' } // or 'start' (top) / 'end' (bottom)
)
});
Caveat: editor.cm is not part of Obsidian’s official public API — but it’s widely used in the plugin ecosystem.
This works well in normal text and in Source Mode. But Live Preview table cells need a different approach — when the cursor is in a table cell, Obsidian creates a separate inner EditorView for that cell, and editor.cm.state.selection.main.head points to a placeholder in the outer view rather than the actual cursor.
For table cell support, window.getSelection() gives the true browser cursor position regardless of inner/outer view. See how it’s implemented in my plugin Universal Cursor Hotkeys (relevant source on GitHub) — it also implements the recenter-top-bottom cycle (center → top → bottom) as a Ctrl+L command.