ProseMirror and Uneditable content in the document

Im trying to build a text editor that has fixed input structures for contextual sections and I’m having issues understanding whats the proper solution.

This is my vision:

Unfortunately, neither the Title (ComputerSpec) nor the tags (Video, etc) should be editable, erasable, navigatible etc.

I’ve tried using the standard nodeSpec reqs to build this:

const noteSchema = new Schema({
  nodes: {
    text: {},
    field: {
      group: 'block',
      content: '(tag|text)*',
      toDOM: () => ['field', 0],
      parseDOM: [{ tag: 'field' }]
    },
    title: {
      group: 'block',
      content: 'text*',
      //editable: false,
      toDOM: () => ['h4', { }, 0],
      parseDOM: [{ tag: 'h4' }],
    },
    tag: {
      content: 'text*',
      inline: true,
      atom: true,
      //editable: false,
      toDOM: () => ['span', { class: 'prose-tag' }, 0],
      parseDOM: [{ tag: 'span' }]
    },
    section: {
      group: 'block',
      content: '(field|title)+',
      toDOM: () => ['section', 0],
      parseDOM: [{ tag: 'section' }]
    },
    doc: {
      content: '(block)+',
    }
  }
});

But they are still editable. I tried “contenteditable=false” attribute with unconvincing results.

Second, I tried doing a plugin and Filter transaction: I could potentially filter transactions that try to delete the node, but many operations like selecting big chunks give some complex transaction data to filter.

Third approach would be to use css pseudo selectors and make the tags and titles outside the document model, or use decorators, but ultimately It’s unconvincingly complicated to do it that way, and they do look like nodes. In the future, I would also like to be able to implement an autocomplete, where you could write “ComputerS…” and after selecting ComputerSpec it creates these elements, so the decoration approach does not look like the right one.

How to go about achieving this? Even just a pointer on how to achieve that with the dino example might suffice.

2 Likes

I think a more promising approach would be to have the schema just express the editable parts of the document, using node types and attributes for the fixed parts (which seem to follow from the document structure), and then rendering them as part of the wrapper nodes for those node types (i.e. an item node with an attribute type that holds the strings like "HARDDRIVE", which renders to something like ["div", {class: "item"}, ["div", {contenteditable: false, class: "itemtype", "HARDDRIVE"], ["div", 0]].

3 Likes

I am looking for something similar to this you have found some solution that you can share

I followed the approach suggested above (use a wrapper to add ‘contenteditable:false’). Here are notes based on my experience:

  • Even with contenteditable:false, the text can still be selected, and deleted if the user uses backspace. To resolve this, I set the CSS attribute ‘user-select:none’ to prevent selection

  • If the user clicks backspace on an editable paragraph immediately after a read-only paragraph, it is possible that the two paragraphs get merged into an editable one. I found that filtering transactions (as suggested on this tiptap forum) is quite useful