How to get a selection Rect?

I want to render a popup menu and I’m having a hard time reliably getting a rect for the selection. Here’s what I originally tried:

function getSelectionRect() {
	const selection = document.getSelection()
	if (selection) {
		const range = selection.getRangeAt(0)
		const rect = range.getBoundingClientRect()
		return rect
	}
}

new Plugin({
	props: {
		handleKeyDown(view, e) {
			const rect = getSelectionRect()

Sometimes it works but every so often (seems deterministic), I get a rect that is all zeroed out. I think that might be because the dom element doesn’t exist anymore? I’m really not sure.

I’ve also tried this which seems like the more ProseMirror way to do it:

const pos = view.state.tr.selection.$from.pos
const parent = view.domAtPos(pos)
const range = document.createRange()
range.setStart(parent.node, parent.offset)
range.setEnd(parent.node, parent.offset)
const rect = range.getBoundingClientRect()

This doesnt seem to work at all though. #EDIT: this actually does work, just not when the cursor is at the end.

What do you think is the best / most reliably way to do this?

Thanks

I just discovered view.coordsAtPos(pos). This is exactly what I needed!

3 Likes

Could you provide an example of usage of the view.coordsAtPos(pos) please?

const {left, right} = view.coordsAtPos(view.state.tr.selection.$from.pos)