Inserting a non-editable text node


Hi, I’m trying to add a node to the schema that would behave much like the dino example. The node is a non-editable piece of text. This is what I came up with for the spec:

  content: "text*",
  inline: true,
  group: "inline",
  draggable: true,
  atom: true,
  defining: true,
  attrs: {
    field: {default: 'personalisation'},
    label: {default: 'personalisation'},
  toDOM(node) {
    return ['span', node.attrs, node.attrs.label]
  parseDom: [
      tag: 'span[field]',
        return {
          field: dom.getAttribute('field'),
          label: dom.getAttribute('label'),

And this is the factory for inserting the node command:

function insertPersonalisationTag(field, label) {
  return function(state, dispatch) {
    let {$from} = state.selection, index = $from.index()
    if (!$from.parent.canReplaceWith(index, index, editorSchema.nodes.personalisationTag))
      return false
    if (dispatch)
      dispatch({field, label})))
    return true

I am extending the basic schema. The code returns false for ‘canReplaceWith’ bit. What am I doing wrong? Thanks.


It seems like you’re trying to define a leaf (content-less node), so you shouldn’t give it a content: "text*" property. defining and atom are meaningless for leaf nodes, so you can drop those too.

That doesn’t explain why canReplaceWith is returning false, though. If the selection is in inline content and your schema uses the "inline" group for that, it should allow inserting there. Are all pieces of your code using the same schema instance?


No, that was it! editorSchema is the editorSchema.nodes.personalisationTag is different from the one related to $from.parent. They use the same nodes, so I assumed it’s fine, but apparently it has to be the same instance?

Btw, thank you so much for your fast responses, you really helped me out and your product is great.

Best, Ivan


Yes, node types are compared by object identity (==), so equivalent types from different schema instances are never compatible.