From zbeyens. The source code is available on GitHub.

Plate
PlatePliteEditorsTemplates
GitHub16kGitHub
DiscordDiscord
UNPUBLISHED
  • Overview
  • Why This Fork
  • Examples
Walkthroughs
  • Installing Plite
  • Adding Event Handlers
  • Defining Custom Elements
  • Applying Custom Formatting
  • Executing Commands
  • Saving to a Database
  • Canonical Change Substrate
  • Improving Performance
Concepts
  • Interfaces
  • Nodes
  • Locations
  • Transforms
  • Document Changes
  • Commands
  • Editor
  • Extensions
  • Rendering
  • Serializing
  • Normalizing
  • Using TypeScript
  • Roots
  • Document State
  • Editing Behavior
  • Selection And DOM
  • Clipboard And Paste
  • Projection And Overlays
  • Schema
API
  • Anchor API
  • Location API
  • Path API
  • PointEntry API
  • Point API
  • Range API
  • Selection API
  • Location Types APIs
  • Span API
  • Editor
  • Element API
  • NodeEntry API
  • Node API
  • Node Types APIs
  • Text API
  • Debug Value Scrubbing
  • Transforms API
Libraries
  • Plite DOM
  • History Editor API
  • History Extension Setup
  • History
  • Plite History
  • Plite Hyperscript
  • Plite Layout
  • Annotations
  • DOM Coverage Boundaries
  • Editable Component
  • Plite React Event Handling
  • Virtualized Rendering
  • Plite React Hooks
  • React Editor Setup
  • React Editor
  • Plite React
  • Plite Component
  • Plite Yjs
  • Plite
General
  • Migration
  • Contributing
  • Docs Proof Map
  • FAQ
  • Resources

Nodes

PreviousNext

Model documents with Element and Text nodes across primary and extra roots.

Plite 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.

Value Shape

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 meta from state fields. Save editor.read.value() when you need the whole document.

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




InterfacesLocations

On This Page

Value ShapeElementTextFinding NodesBlocks And InlinesVoidsNode Tree Rules
Build your editor
Production-ready AI template and reusable components.
Get all-access
],
meta: {
"document.title": "Draft",
},
};
const documentValue = {
  children: [
    {
      type: "paragraph",
      children: [{ text: "A line of text!" }],
    },
  ],
  meta: {
    "document.title": "Draft",
  },
};

The short editor value is still an array of block elements. Plite 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 Meta for persistence and Roots for extra roots, content roots, and multi-root rendering.

Element

Elements make up the structure of a Plite 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,
};

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

Finding Nodes

Use namespaced node reads for tree queries. type selects structural node types. match adds a predicate.

const callout = editor.read.nodes.find({
  type: "callout",
});
 
const tableNode = editor.read.nodes.find({
  type: ["table", "table_cell"],
});
const callout = editor.read.nodes.find({
  type: "callout",
});
 
const tableNode = editor.read.nodes.find({
  type: ["table", "table_cell"],
});

An array selects any listed type. Use a predicate when the condition is computed or when it should narrow the returned node type.

When component code already owns a text or element node, pass that node to a public at option instead of resolving its path first. See Locations.

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 behavior and child grammar in the schema.

import { defineExtension, property, schema } from "@platejs/plite";
 
const Links = defineExtension("links", {
  schema: {
    elements: {
      link: {
        content: schema.content.text({ default: "text", min: 1 }),
        inline: true,
        properties: {
          url: property.string(),
        },
      },
    },
  },
});
import { defineExtension, property, schema } from "@platejs/plite";
 
const Links = defineExtension("links", {
  schema: {
    elements: {
      link: {
        content: schema.content.text({ default: "text", min: 1 }),
        inline: true,
        properties: {
          url: property.string(),
        },
      },
    },
  },
});

Non-inline elements automatically belong to the compiler-owned block group. Inline elements declare inline: true and automatically belong to inline. Use groups only for application-specific semantic groupings.

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 in an extension schema.

import { defineExtension, property } from "@platejs/plite";
 
const Images = defineExtension("images", {
  schema: {
    elements: {
      image: {
        properties: {
          url: property.string(),
        },
        void: "block",
      },
    },
  },
});
import { defineExtension, property } from "@platejs/plite";
 
const Images = defineExtension("images", {
  schema: {
    elements: {
      image: {
        properties: {
          url: property.string(),
        },
        void: "block",
      },
    },
  },
});

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

Plite keeps document trees valid while transaction writes 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 Schema for declarations, compiled validation, and fitting. See Normalizing for semantic corrections that run after schema-valid writes.