For an original example, a help-center editor needs a short caution panel containing one or more paragraphs. The panel should survive saving and reopening as a caution node. A yellow paragraph alone cannot tell a later renderer whether the author intended a caution or merely chose a background color.
Give the panel a place in the document grammar
This minimal schema supports paragraphs, a caution container, and text:
import { Schema } from 'prosemirror-model';
const supportSchema = new Schema({
nodes: {
doc: { content: 'block+' },
paragraph: {
group: 'block',
content: 'text*',
parseDOM: [{ tag: 'p' }],
toDOM() { return ['p', 0]; }
},
caution: {
group: 'block',
content: 'paragraph+',
parseDOM: [{ tag: 'aside[data-kind="caution"]' }],
toDOM() { return ['aside', { 'data-kind': 'caution' }, 0]; }
},
text: {}
}
});
Use this in an application build that resolves prosemirror-model. It defines a model, not an entire editor with menus, keymaps, or persistence. Add compatible state and view setup separately.
block+ requires at least one block. The caution's paragraph+ requires at least one paragraph and prevents a caution from directly containing another caution. text* allows an empty paragraph, which gives the author somewhere to type. Paragraph appears first among the block nodes so default filler content can be a simple paragraph.
There are no marks in this deliberately small schema. If authors need links or emphasis, define those marks and their parsing and serialization rules. Expanding the schema changes the document formats the application must support.
Create a valid caution and check imported data
Build the example through the schema's node types:
const paragraph = supportSchema.nodes.paragraph.createChecked(
null,
supportSchema.text('Disconnect the test unit before changing its cable.')
);
const caution = supportSchema.nodes.caution.createChecked(null, paragraph);
const helpDocument = supportSchema.nodes.doc.createChecked(null, [caution]);
helpDocument.check();
createChecked() checks the node's content against its type. The ordinary create() method does not provide the same content validation. Node.check() checks the resulting node and its descendants. Model API
When loading stored JSON, preserve the original input if validation fails:
const restored = supportSchema.nodeFromJSON(savedDocumentJson);
restored.check();
Here savedDocumentJson is a previously parsed JSON object, not its JSON string. Catch exceptions in the application's load boundary and show an appropriate recovery path. Do not replace a failed record with an empty document and report a successful load.
Keep parsing and serialization paired
The caution's parsing selector recognizes an explicit data-kind attribute. Its serializer writes that attribute again. The 0 in each toDOM array marks where child content belongs; it is not visible text.
For a browser-side export:
import { DOMSerializer } from 'prosemirror-model';
const wrapper = document.createElement('div');
wrapper.appendChild(
DOMSerializer.fromSchema(supportSchema)
.serializeFragment(helpDocument.content)
);
const exportedHelpHtml = wrapper.innerHTML;
The output should retain the aside wrapper and its paragraph. Add the receiving page's caution styling separately. Parsing with a schema is a representation policy; it should not be presented as a complete sanitizer or authorization system for arbitrary supplied HTML.
Prove the round trip before widening the schema
Save helpDocument.toJSON() through the application's document service, restore it with this schema, and check that its first child is still a caution containing the cable instruction. Export it and import that HTML through the matching schema-aware DOM parser. Compare the resulting structure and wording, rather than requiring byte-for-byte identical HTML formatting.
The decoration guide covers temporary visual highlights. This caution belongs in document content because it must survive export. Keep the grammar small enough that every supported node has a deliberate editing, storage, and reader-rendering path.