Selection in nodeViews outside of contentDOM

Hey, is it possible that something has changed in how the selection and nodeviews interact? I used to have it working where the selection caret would move directly from after A to before C and from after C to before E when moving it between nodes using the right arrow key:

<p>A</p>

<div class="dom">B<span class="content-dom">C</span>D</div>

<p>E</p>

But not instead the caret moved from after A to before B. The user can actually type things inside of div.dom outside of span.content-dom. If I add a contentEditable=false on div.dom and contentEditable=true on span.content-dom then the user can no longer modify the outer part of div.dom, but the caret also no longer moved between A, C and E using the arrow right/left keys.

I’m not aware of anything related to this changing, but if you can pinpoint a prosemirror-view version where something changed, I can take a look.

I cannot. I tried last night to go back some versions and didn’t get it to work in older versions either. I am thinking that maybe it is in Chrome’s selection related code that there has been a change. Or maybe I somehow overlooked this issue hitherto.

If you have a nodeview for a node with content and you don’t want to let the user modify the DOM of the nodeview’s shell but do allow the user to modify the content via prosemirror, is it recommended that you add a contenteditable=false attribute on the nodeview’s dom and contenteditable=true on the nodeview’s contentDOM?

No, that is usually a bad idea (you won’t be able to select from inside the node to outside it anymore). Sometimes you can get somewhere by wrapping the uneditable parts in an uneditable node (but there’s lot of weird browser behavior that can still trip you up there).

I basically have this:

<p>...</p>
<nodeview-dom>
    <nodeview-content-dom>...</nodeview-content-dom>
    <button>Label</button>
</nodeview-dom>
<p>...</p>

I recently discovered that the user could move the caret and enter new text in the button label (not delete though). I am convinced that this wasn’t possible earlier, but it seems to be unrelated to prosemirror. So I first tried this:

<p>...</p>
<nodeview-dom>
    <nodeview-content-dom>...</nodeview-content-dom>
    <button contenteditable=false>Label</button>
</nodeview-dom>
<p>...</p>

That made the caret no longer be able to go inside the button. But instead it could go here (| = caret) and add content there:

<p>...</p>
<nodeview-dom>blablabla|
    <nodeview-content-dom>...</nodeview-content-dom>
    <button contenteditable=false>Label</button>
</nodeview-dom>
<p>...</p>

So then I did:

<p>...</p>
<nodeview-dom contenteditable=false>
    <nodeview-content-dom contenteditable=true>...</nodeview-content-dom>
    <button>Label</button>
</nodeview-dom>
<p>...</p>

It has the disadvantage that you mention and it also seems impossible to move the caret between the inner contenteditable and the outer one, but at least the caret the user can no longer edit the button label.

If there is a better way of doing this, I’d be very much interested.

Hey @johanneswilm, I have the same problem with tiptap. Have you ever found a better solution?

I currently create a CSS sheet dynamically and add it to the document head. In that stylesheet I then add the text that should not be editable using the ::before selector and the content property. The native selection doesn’t recognize CSS text that was added using CSS. It’s a bit of a hack, btu it also seems to be working.

1 Like

Hi everyone, I’ve also run into this problem.

I have a custom figure NodeView which may contain a figcaption that is editable (set as contentDOM). Unfortunately, the cursor can move beyond the boundaries of the <figcaption> to before and after the <img>.

Since that content is an image and not simply text, I cannot use @johanneswilm’s workaround. Is there anything else that I could do?

How about using ::before to add a block with a background image?

Thank you for your suggestion. I guess using a background-image would bring all sorts of sizing issues with it—I was able to solve this by wrapping the <img> into a <div> with contenteditable="false". Since it’s a NodeView, I don’t mind the additional wrapper-element.