Schema
Overview
Each ProseMirror document has a schema associated with it. The schema describes the kind of nodes that may occur in the document, and the way they are nested. For example, it might say that the top-level node can contain one or more blocks, and that paragraph nodes can contain any number of inline nodes, with any marks applied to them.
The schema is crucial for ensuring document consistency. It helps ProseMirror understand how to parse, validate, and serialize your document.
Schema property
- Nodes: Block-level elements like paragraphs, headings, lists, etc.
- Marks: Inline formatting like bold, italic, links, etc.
Nodes
Nodes represent block-level elements like paragraphs, headings, and lists.
Node Properties
- content: Defines allowed child nodes
- group: Assigns the node to a group
- inline: Boolean, true for inline nodes
- atom: Boolean, true for leaf nodes
- attrs: Defines attributes for the node
- toDOM: Function to convert node to DOM
- parseDOM: Rules for parsing DOM to node
Node Example
nodes: {
paragraph: {
content: "inline*",
group: "block",
parseDOM: [{tag: "p"}],
toDOM() { return ["p", 0] }
},
heading: {
attrs: {level: {default: 1}},
content: "inline*",
group: "block",
defining: true,
parseDOM: [{tag: "h1", attrs: {level: 1}},
{tag: "h2", attrs: {level: 2}},
{tag: "h3", attrs: {level: 3}}],
toDOM(node) { return ["h" + node.attrs.level, 0] }
}
}
Marks
Marks represent inline formatting like bold, italic, or links.
Mark Properties
- attrs: Defines attributes for the mark
- inclusive: Boolean, determines mark boundaries
- excludes: Specifies incompatible marks
- group: Assigns the mark to a group
- spanning: Boolean, allows mark to span multiple nodes
- toDOM: Function to convert mark to DOM
- parseDOM: Rules for parsing DOM to mark
Mark Example
marks: {
strong: {
parseDOM: [{tag: "strong"}, {tag: "b"}, {style: "font-weight", getAttrs: value => value == "bold" && null}],
toDOM() { return ["strong", 0] }
},
link: {
attrs: {
href: {},
title: {default: null}
},
inclusive: false,
parseDOM: [{tag: "a[href]", getAttrs(dom) {
return {href: dom.getAttribute("href"), title: dom.getAttribute("title")}
}}],
toDOM(node) { return ["a", node.attrs, 0] }
}
}
Example of a basic schema
import { Schema } from "prosemirror-model";
const schema = new Schema({
nodes: {
paragraph: {
content: "inline*",
group: "block",
parseDOM: [{ tag: "p" }],
toDOM() {
return ["p", 0];
},
},
heading: {
attrs: { level: { default: 1 } },
content: "inline*",
group: "block",
defining: true,
parseDOM: [
{ tag: "h1", attrs: { level: 1 } },
{ tag: "h2", attrs: { level: 2 } },
{ tag: "h3", attrs: { level: 3 } },
],
toDOM(node) {
return ["h" + node.attrs.level, 0];
},
},
},
marks: {
strong: { toDOM: () => ["strong", 0] },
em: { toDOM: () => ["em", 0] },
},
});
Content Expressions
Content expressions define valid child structures:
- "paragraph+": One or more paragraphs
- "heading block*": A heading followed by zero or more blocks
- "(paragraph | blockquote)+": One or more paragraphs or blockquotes
Groups
Groups allow you to refer to multiple node types:
nodes: {
paragraph: { group: "block", ... },
blockquote: { group: "block", ... },
heading: { group: "block", ... },
code_block: { group: "block", ... }
}