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

History Editor API

PreviousNext

Read history state, replay complete batches, and control history grouping.

History adds an owner-local read group, a replay service, and transaction controls for the update being built.

Read API

editor.read.history(): History

Read the full history value.

editor.read.history.hasUndo(): boolean

Plite DOMHistory Plugin Setup

On This Page

Read APIeditor.read.history(): Historyeditor.read.history.hasUndo(): booleaneditor.read.history.hasRedo(): booleaneditor.read.history.pending(): "undo" | "redo" | nullReplay serviceeditor.api.history.undo(): HistoryResulteditor.api.history.redo(): HistoryResultTransaction APItx.history.skip(): voidtx.history.merge(): voidtx.history.newBatch(): voidUpdate policyeditor.update({ history: "skip" }, fn): R | undefinededitor.update({ history: "merge" }, fn): R | undefinededitor.update({ history: "new-batch" }, fn): R | undefinedTypes
Build your editor
Production-ready AI template and reusable components.
Get all-access

Return whether the undo branch has a surviving mapped batch.

editor.read.history.hasRedo(): boolean

Return whether the redo branch has a surviving mapped batch.

editor.read.history.pending(): "undo" | "redo" | null

Return the replay direction currently waiting for a live-session owner. Pending state belongs to this editor runtime and is not included in History JSON, snapshots, or collaboration.

Use editor.read.history().undos and editor.read.history().redos when you need the full immutable arrays. The same group is available as state.history inside editor.read((state) => ...).

Replay service

editor.api.history.undo(): HistoryResult

Claim and replay the current undo batch.

editor.api.history.redo(): HistoryResult

Claim and replay the current redo batch.

type HistorySettlement =
  | Readonly<{ status: "applied" }>
  | Readonly<{ reason: string; status: "blocked" }>
  | Readonly<{ status: "failed" }>;
 
type HistoryResult =
  | HistorySettlement
  | Readonly<{ status: "busy" | "empty" }>
  | Readonly<{ conflicts: readonly string[]; status: "blocked" }>
  | Readonly<{ settled: Promise<HistorySettlement>; status: "pending" }>;
type HistorySettlement =
  | Readonly<{ status: "applied" }>
  | Readonly<{ reason: string; status: "blocked" }>
  | Readonly<{ status: "failed" }>;
 
type HistoryResult =
  | HistorySettlement
  | Readonly<{ status: "busy" | "empty" }>
  | Readonly<{ conflicts: readonly string[]; status: "blocked" }>
  | Readonly<{ settled: Promise<HistorySettlement

Both methods claim the current branch head and return synchronously. A document batch has applied when the call returns. A live-session batch whose owner is still working returns pending and publishes its pending direction until settled resolves; settled never rejects. Document edits, selection updates, and collaborative imports continue during that wait; another replay returns busy without claiming a batch.

blocked reports a refusal from the live-session owner. failed means the owner or the settlement threw; the error goes to the editor's lifecycleErrorSink. With no sink, it goes to reportError, or to console.error where reportError does not exist. blocked and failed both keep that batch at the branch head. Invalid runtime use, such as a replay inside an active read or update, throws. Replay always applies the complete document-wide batch, including changes in other roots.

Transaction API

tx.history.skip(): void

Do not save the current transaction to history.

tx.history.merge(): void

Merge the current transaction into the previous compatible undo batch.

tx.history.newBatch(): void

Start a fresh undo batch for the current transaction.

Update policy

editor.update({ history: "skip" }, fn): R | undefined

Run one update without saving it to history.

editor.update({ history: "merge" }, fn): R | undefined

Run one update that merges into the previous compatible undo batch.

editor.update({ history: "new-batch" }, fn): R | undefined

Run one update where the first write starts a fresh history batch, then the rest of the callback merges into that batch.

Configure a direct write by calling editor.update(policy) first.

editor.update({ history: "skip" }).text.insert("draft");
editor.update({ history: "skip" }).text.insert("draft");

Types

import type {
  DocumentChange,
  EditorEffect,
  EditorSchemaIdentity,
  Selection,
} from "plitejs";
 
type History = {
  readonly redos: readonly Batch[];
  readonly revision: number;
  readonly schema: EditorSchemaIdentity;
  readonly undos: readonly Batch[];
};
 
type Batch = {
  readonly change: DocumentChange;
  readonly effects: readonly EditorEffect[];
  readonly selectionAfter: Selection;
  readonly selectionAfterRoot?: string;
  readonly selectionBefore: Selection;
  readonly selectionBeforeRoot?: string;
};
import type {
  DocumentChange,
  EditorEffect,
  EditorSchemaIdentity,
  Selection,
} from "plitejs";
 
type History = {
  readonly redos: readonly Batch[];
  readonly revision: number;
  readonly schema: EditorSchemaIdentity;
  readonly undos: readonly Batch[];
};
 
type Batch = {
  readonly change: DocumentChange;
  readonly effects: readonly EditorEffect[];




Persist the installed stacks with History.toJSON(editor). Decode them with History.fromJSON(editor, json), then install the returned value through tx.history.restore(...). Custom standalone effects belong to an installed plugin's effects resource so their keyed versioned codecs can decode the batch. The version 4 envelope requires the current derived or named schema identity and rejects null or mismatched schema semantics before decoding a batch.

Compatible typing and same-node property updates coalesce from canonical DocumentChange classifications and changed ranges. Grouping fingerprints are runtime-only; loading persisted history starts a fresh automatic group.

>;
status
:
"pending"
}>;
readonly selectionAfter: Selection;
readonly selectionAfterRoot?: string;
readonly selectionBefore: Selection;
readonly selectionBeforeRoot?: string;
};