Plate
PlateEditorsTemplates
GitHub16kGitHub
DiscordDiscord
    • Overview
    • Why This Fork
    • Examples
    • Installing Plite
    • Adding Event Handlers
    • Defining Custom Elements
    • Applying Custom Formatting
    • Executing Commands
    • Saving to a Database
    • Canonical Change Substrate
    • Improving Performance
    • Interfaces
    • Nodes
    • Locations
    • Transforms
    • Document Changes
    • Commands
    • Editor
    • Plugins
    • Rendering
    • Serializing
    • Normalizing
    • Using TypeScript
    • Roots
    • Document State
    • Editing Behavior
    • Selection And DOM
    • Clipboard And Paste
    • Decorations, annotations, and widgets
    • Schema
    • 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
    • Plite DOM
    • History Editor API
    • History Plugin Setup
    • History
    • Plite History
    • Plite Hyperscript
    • Plite PaginationExperimental
    • Annotations
    • DOM Coverage Boundaries
    • Editable Component
    • External Text Views
    • Plite React Event Handling
    • Virtualized Rendering
    • Plite React Hooks
    • React Editor Setup
    • React Editor
    • Plite React
    • Plite Component
    • Plite Yjs
    • Plite
    • Migration
    • Contributing
    • FAQ
    • Resources

Interfaces

PreviousNext

Understand the plain JSON interfaces that make up Plite documents.

Plite documents are plain JSON objects with a small set of structural interfaces. Your app owns the product-specific fields.

Text

Text nodes contain text plus optional mark properties.

interface Text {
  readonly text: string;
  readonly [key: string]: unknown;
}
interface


Improving PerformanceNodes

On This Page

TextElementHelper namespacesDomain helpers
Build your editor
Production-ready AI template and reusable components.
Get all-access
Text
{
readonly text: string;
readonly [key: string]: unknown;
}
const text = {
  text: "Bold",
  bold: true,
};
const text = {
  text: "Bold",
  bold: true,
};

Plite treats bold as your data. The editor only requires the text string.

Element

Elements contain child nodes and any product fields your schema needs.

interface Element {
  readonly children: readonly Descendant[];
  readonly type: string;
  readonly [key: string]: unknown;
}
interface Element {
  readonly children: readonly Descendant[];
  readonly type: string;
  readonly [key: string]: unknown;
}
const paragraph = {
  type: "paragraph",
  children: [{ text: "Body" }],
};
 
const link = {
  type: "link",
  url: "https://example.com",
  children: [{ text: "Example" }],
};
const paragraph = {
  type: "paragraph",
  children: [{ text: "Body" }],
};
 
const link = {
  type: "link",
  url: "https://example.com",
  children: [{ text: "Example" }],
};

Plite requires a type string on every element and uses it to resolve schema behavior. Your app defines the element types and custom fields such as url.

const LinkElement = ({ attributes, children, element }) => {
  return (
    <a {...attributes} href={element.url}>
      {children}
    </a>
  );
};
const LinkElement = ({ attributes, children, element }) => {
  return (
    <a {...attributes} href={element.url}>
      {children}
    </a>
  );
};

Helper namespaces

Runtime values use plain objects. Static helper functions live on *Api namespaces such as NodeApi, ElementApi, TextApi, PathApi, PointApi, RangeApi, and SelectionApi.

import { ElementApi, NodeApi, RangeApi } from "plitejs";
 
const string = NodeApi.string(element);
const isElement = ElementApi.isElement(value);
const collapsed = RangeApi.isCollapsed(range);
import { ElementApi, NodeApi, RangeApi } from "plitejs";
 
const string = NodeApi.string(element);
const isElement = ElementApi.isElement(value);
const collapsed = RangeApi.isCollapsed(range);

Use the helper namespace when you need structural checks, path math, range direction, or text extraction outside an editor read/update callback.

Inside editor.read(...) and editor.update(...), prefer the grouped runtime helpers because they understand the current root, schema, and transaction.

const linkEntry = editor.read((state) =>
  state.nodes.above({
    match: (node) => ElementApi.isElement(node) && node.type === "link",
  })
);
const linkEntry = editor.read((state) =>
  state.nodes.above({
    match: (node) => ElementApi.isElement(node) && node.type === "link",
  })
);

Domain helpers

Keep domain helpers as normal functions or expose them from an plugin when they need editor state.

import { ElementApi, type Element } from "plitejs";
 
type ImageElement = Element & {
  type: "image";
  url: string;
};
 
const isImageElement = (value: unknown): value is ImageElement =>
  ElementApi.isElement(value) &&
  value.type === "image" &&
  typeof value.url === "string";
import { ElementApi, type Element } from "plitejs";
 
type ImageElement = Element & {
  type: "image";
  url: string;
};
 
const isImageElement = (value: unknown): value is ImageElement =>
  ElementApi.isElement(value) &&
  value.type === "image" &&
  typeof value.url === "string";

Use Plugins when a helper should become a typed state, tx, or api namespace installed on the editor.