Respect focus with preventScroll

I am implementing a table of contents that needs to:

a) Smooth scroll to an element b) Focus the element

I am doing this by calling:

let top = el.offsetTop;
parent.scrollTo({top: top, behavior: "smooth"});
el.focus({preventScroll: true})

This works fine on plain input components, but when focusing the Prosemirror DOM node, it seems like the focus will also scroll to the cursor, even when preventScroll is requested. This makes me suspect that there’s a listener somewhere for the focus event, which will do something that will cause the scroll to change.

I’m not sure what’s the best way to tackle this in Prosemirror, but at the very least, being able to call .focus({preventScroll: true}) on the view itself, would allow me to detect PM dom nodes and call their focus function, instead of the DOM node…

You’ll notice that this happens on Chrome but not Firefox, because Chrome (and possibly also Safari, I can’t remember) will reset the selection when you focus an editable element, moving it to the start of the element. ProseMirror includes a workaround that restores the previous selection in this case and, as you notice, scrolls it back into view. Unfortunately, at the point where that hack runs, it doesn’t have enough information to know whether the scroll position it sees is the result of the browser scrolling the start of the document into view or not.

The workaround for you would be to call view.focus() instead of the DOM focus method. That won’t scroll (or rather, that will properly counteract the browser’s inappropriate scrolling), and will make sure the selection is where it should be.