Single paragraph editing

Hello, I’m trying to mount ProseMirror to a single paragraph element to allow for basic styling (strong, em, anchors, br etc) without inserting child <p> nodes.

This is what I’ve come up with so far:

<p id="editor">
  Some initial content <span>with spans</span><br>
  and <strong>bold text</strong>.
</p>

const element = document.getElementById('editor')

const schema = new Schema({
    nodes: {
        text: {
            group: "inline",
        },
        paragraph: {
            group: "block",
            content: "inline*",
            toDOM() {
                return ['', 0] // Trying to prevent child <p> nodes.
            },
            parseDOM: [{
                tag: "p"
            }],
        },
        doc: {
            content: 'paragraph',
        },
    }
})

const editorState = EditorState.create({
    doc: DOMParser.fromSchema(schema).parse(element),
})

let view = new EditorView(
    { mount: element! },
    {
        state: editorState,
    }
)

This throws the exception:

Uncaught DOMException: String contains an invalid character

from prosemirror-model/src/to_dom.ts at 1cbef0f8762c0e6030555ee3f5dab81785efd7e5 · ProseMirror/prosemirror-model · GitHub

Is this the correct approach? I feel like I’m close, but missing some understanding.

The editing functionality appears to be working, the use of the text node type works well but strips inline tags and does not allow for line-breaks which lead me to try the paragraph type.

Make paragraph your top-level node and drop the doc node type. Returning ['', 0] from toDOM to avoid creating a node is not something that works.

1 Like

Brilliant! This worked perfectly, thank you! I had missed the topNode property while reading the docs. I also needed to append the marks from prosemirror-schema-basic to provide coverage for the inline elements.

Working code below for posterity.

<p id="editor">
  Some initial content <span>with spans</span><br>
  and <strong>bold text</strong>.
</p>

const element = document.getElementById('editor')

const mySchema = new Schema({
    nodes: {
        text: {
            group: "inline",
        },
        paragraph: {
            group: "block",
            content: "inline*",
            toDOM() {
                return ['p', 0]
            },
            parseDOM: [{
                tag: "p"
            }],
        },
    },
    marks: schema.spec.marks, // TODO: Requires extension via .append({...}) to cover `<span>` tag and attributes
    topNode: 'paragraph',
})

const editorState = EditorState.create({
    doc: DOMParser.fromSchema(mySchema).parse(element),
})

new EditorView(
    { mount: element! },
    {
        state: editorState,
    }
)

Thank you for the prompt response, much appreciated. Really good bit of kit!

1 Like