Document
The Document node is the invisible root of every editor. It wraps all top-level content and defines the document structure. You never render it directly, but every editor requires it.
Document is included in StarterKit. If you are building a custom setup without StarterKit, add it manually:
import { Editor, Document, Text, Paragraph } from '@domternal/core';
const editor = new Editor({ element: document.getElementById('editor')!, extensions: [Document, Text, Paragraph], content: '<p>Hello world</p>',});import { Component, signal } from '@angular/core';import { DomternalEditorComponent } from '@domternal/angular';import { Editor, Document, Text, Paragraph } from '@domternal/core';
@Component({ selector: 'app-editor', imports: [DomternalEditorComponent], template: ` <domternal-editor [extensions]="extensions" [content]="content" (editorCreated)="editor.set($event)" /> `,})export class EditorComponent { editor = signal<Editor | null>(null); extensions = [Document, Text, Paragraph]; content = '<p>Hello world</p>';}import { Domternal } from '@domternal/react';import { Document, Text, Paragraph } from '@domternal/core';
export default function Editor() { return ( <Domternal extensions={[Document, Text, Paragraph]} content="<p>Hello world</p>" > <Domternal.Content /> </Domternal> );}Document is always required. It defines the root of the document tree but has no visual output or commands. Every editor setup must include Document, Text, and Paragraph as the minimum.
import { Editor, Document, Text, Paragraph } from '@domternal/core';
const editor = new Editor({ extensions: [Document, Text, Paragraph], content: '<p>Hello world</p>',});
// Access the document nodeconst doc = editor.state.doc;console.log(doc.childCount); // Number of top-level blocksconsole.log(doc.textContent); // Plain text of entire documentSchema
Section titled “Schema”| Property | Value |
|---|---|
| ProseMirror name | doc |
| Type | Node |
| Top node | Yes |
| Content | block+ |
| Group | None |
| Rendered in DOM | No |
The block+ content expression means the document must contain at least one block-level node (such as a Paragraph, Heading, or Blockquote). If you create an editor with null or empty content, the document automatically starts with one empty paragraph.
JSON representation
Section titled “JSON representation”When you call editor.getJSON(), the document is the outermost node:
{ "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "Hello world" } ] } ]}You can use this format to set or restore editor content:
editor.setContent({ type: 'doc', content: [ { type: 'paragraph', content: [{ type: 'text', text: 'Hello world' }], }, ],});The same JSON structure is accepted by the SSR helpers generateHTML and generateText for server-side rendering without a browser DOM.
Customizing the content model
Section titled “Customizing the content model”By default, Document accepts any block nodes (block+). You can extend it to restrict the content model. For example, to enforce that the first child is always a heading:
import { Document } from '@domternal/core';
const CustomDocument = Document.extend({ content: 'heading block*',});This schema requires a Heading as the first node, followed by zero or more block nodes. ProseMirror enforces the content model, so the editor will not allow the user to delete the heading.
Other useful content expressions:
| Expression | Meaning |
|---|---|
block+ | One or more block nodes (default) |
heading block* | A heading followed by any block nodes |
(heading | paragraph) block* | A heading or paragraph first, then any block nodes |
block{1,10} | Between 1 and 10 block nodes |
Options
Section titled “Options”Document has no configurable options.
Commands
Section titled “Commands”Document adds no commands.
Keyboard shortcuts
Section titled “Keyboard shortcuts”Document adds no keyboard shortcuts.
Source
Section titled “Source”@domternal/core - Document.ts