Nodes

PreviousNext

Slate documents are JSON trees. The editable content in each root is built from two node types:

  • Element nodes hold structure and contain child nodes.
  • Text nodes hold string content and mark properties.

The editor runtime can also act as the root ancestor for node APIs, but the persisted document value is primary children, optional extra roots, and optional state fields. Save state.value.get() when you need the whole document.

const documentValue = {
  children: [
    {
      type: 'paragraph',
      children: [{ text: 'A line of text!' }],
    },
  ],
  state: {
    'document.title': 'Draft',
  },
}
const documentValue = {
  children: [
    {
      type: 'paragraph',
      children: [{ text: 'A line of text!' }],
    },
  ],
  state: {
    'document.title': 'Draft',
  },
}

The short editor value is still an array of block elements. Slate treats that array as the primary document.

const initialValue = [
  {
    type: 'paragraph',
    children: [{ text: 'A line of text!' }],
  },
]
const initialValue = [
  {
    type: 'paragraph',
    children: [{ text: 'A line of text!' }],
  },
]

See Document State for persistence and Roots for extra roots, content roots, and multi-root rendering.

Element

Elements make up the structure of a Slate document. They are the nodes that are custom to your product domain.

interface Element {
  children: Node[]
}
interface Element {
  children: Node[]
}

A paragraph, quote, heading, link, image, or custom card is an element. Element properties are yours to define.

const paragraph = {
  type: 'paragraph',
  children: [{ text: 'Hello' }],
}
 
const link = {
  type: 'link',
  url: 'https://example.com',
  children: [{ text: 'Example' }],
}
const paragraph = {
  type: 'paragraph',
  children: [{ text: 'Hello' }],
}
 
const link = {
  type: 'link',
  url: 'https://example.com',
  children: [{ text: 'Example' }],
}

All elements have children. Void elements still keep a text child in the model so selection, marks, copy/paste, and normalization have a stable location.

const image = {
  type: 'image',
  url: 'https://example.com/image.png',
  children: [{ text: '' }],
}
const image = {
  type: 'image',
  url: 'https://example.com/image.png',
  children: [{ text: '' }],
}

Text

Text nodes are leaves. They contain the string plus any mark properties.

interface Text {
  text: string
}
interface Text {
  text: string
}

Marks are normal custom properties on text nodes.

const boldText = {
  text: 'Bold',
  bold: true,
}
const boldText = {
  text: 'Bold',
  bold: true,
}

Slate splits adjacent text into leaves for rendering when decorations or marks change, but the document model is still text nodes inside elements.

Blocks And Inlines

Elements default to block behavior. A block element can only be a sibling of other block elements.

Inline elements live in text flow. Links, mentions, and inline equations are typical inline elements. Inline elements can be siblings with text nodes and other inline elements.

Declare inline behavior with element specs.

const links = defineEditorExtension({
  name: 'links',
  elements: [
    {
      type: 'link',
      inline: true,
    },
  ],
})
const links = defineEditorExtension({
  name: 'links',
  elements: [
    {
      type: 'link',
      inline: true,
    },
  ],
})

Inline nodes cannot be the first or last child of a block and cannot sit next to another inline without a text node between them. Slate's normalizer inserts empty text nodes where the model needs spacing.

Voids

Void elements render visible content without making their own children directly editable. Use voids for images, embeds, mentions, horizontal rules, and other objects that behave as a single editor unit.

Declare void behavior with element specs.

const images = defineEditorExtension({
  name: 'images',
  elements: [
    {
      type: 'image',
      void: true,
    },
  ],
})
const images = defineEditorExtension({
  name: 'images',
  elements: [
    {
      type: 'image',
      void: true,
    },
  ],
})

The React runtime owns the hidden editable anchor and selection shell for voids. App renderers return the visible content through Editable's renderVoid prop. See Element API for a complete rendering example.

Node Tree Rules

Slate keeps document trees valid while operations run.

  • Roots contain block elements.
  • Elements contain either block children or inline/text children, not both.
  • Every element has at least one text descendant.
  • Text nodes merge with adjacent text nodes that have matching marks.
  • Inline and void elements get empty text spacing where selection needs it.

See Normalizing for the full set of built-in constraints and custom normalization hooks.