Mark with a custom 'node' view that defines its own content

Hi everyone.

When rendering static output, I’d like to use a custom node view for links - most of our code is React, and we have standard components that implement some optimisations for our site.

If the link was rendered in the schema as a node rather than a mark, I believe this would work just fine with a custom node view. However, with marks the content of the node appears to get stomped, even if you provide a custom node view to render it.

i.e. with a configuration where links are in the schema as marks and this nodeView exists:

link: (node, view, getPos) => {
    if (editable) {
        return {}; // No custom node view while editing.
    } else {
        const Link = require('uiKit/link');  // Our standard link component
        const span = document.createElement('span');
        ReactDOM.render(<Link {...node.attrs}>{node.textContent}</Link>, span);
        return {
            dom: reactLink,
        }
    }
},

the unfortunate outcome will be that when the document isn’t editable, the result will be a span containing the mark’s content instead of a Link component.

The use of React isn’t actually important here, if I set the span’s innerHtml to ‘bubblegum’ or whatever it will still get stomped.

Should I be converting my links to inline nodes rather than marks, or is there a way to get marks with a custom view to not stomp the dom node’s content?

1 Like

Node views don’t apply to marks, and don’t exist when rendering the document statically via a DOMSerializer. In general, marks are rendered separately from their content (the content is inserted into them after rendering), and their rendering functions don’t even get to see the content yet. So you’ll either have to adjust to that, or define an entirely custom static renderer (which also isn’t very hard).

Ah ok, thanks for the clarification.

I assume implementing a custom DOMSerializer will have the same problem with marks not having access to their own content, right? So by a custom static renderer do you mean taking the document state from ProseMirror and rendering it without using ProseMirror’s API, e.g. with React components? Or is there a way to customize a DOMSerializer to give me access to render marks having control over their content?

PS. Note the documentation on nodeViews implies it works for marks too, which I suppose it does other than their content.

Allows you to pass custom rendering and behavior logic for nodes and marks. Should map node and mark names to constructor function that produce a NodeView object implementing the node’s display behavior. …

I mean just write a recursive function that spits out DOM/HTML – you can do anything, including letting marks render their own content.

1 Like

We did this in ruby for our sites. It was daunting and then it was done in about a day.

1 Like

I would love to an example of this. I’m running into so weird things since Links are Marks. I want to be able to display a form for editing a Link that shows up right next to it. We have it working now, but it’s not exactly pretty.

1 Like