All comparisons

Engine ↔ Engine + product

SpineEditor vs Lexical

Lexical is the editor framework Meta built for Facebook, Workplace, and Messenger. It fuses an editor engine (the model layer and reconciler) with a React-first product layer (@lexical/react, decorator nodes, ready-made plugins, Yjs collab). SpineEditor sits at the engine layer only — framework-neutral, focused on the pipeline contract.

Where they sit

  • Lexical = engine + product. One package family provides both the model engine and React-coupled product features.
  • SpineEditor = engine. The foundational layer that produces plans, transactions, and committed state. The UI and any framework integration live above it.

What Lexical does well

  • Performance. The reconciler updates the DOM in minimal patches; designed for very large documents and many concurrent users.
  • Accessibility. ARIA, screen-reader, and IME handling validated against Meta-scale workloads.
  • React-first ergonomics. @lexical/react provides a clean component API and decorator nodes for embedding React components inside the document.
  • Yjs integration. First-class real-time collaboration through @lexical/yjs.

What SpineEditor does at the engine layer

  • Pipeline as plain data. Lexical state updates run inside editor.update(() => ...) callbacks. SpineEditor compiles every Intent into an explicit Plan, then a Transaction — both plain, serializable data you can inspect, log, or replay.
  • Framework-neutral. The DOM runtime mounts into any HTMLElement; React isn't in the loop.
  • Determinism contract. Six fixed stages produce named artifacts, every commit, no exceptions.
  • Trace and replay built in. Trace tags on every stage, no custom tooling needed.

Engine layer comparison

Architectural layer

Lexical (engine layer)
Engine + product
SpineEditor
Engine

Edit primitive

Lexical (engine layer)
editor.update() callback
SpineEditor
Intent → Plan → Transaction

Explicit plan artifact

Lexical (engine layer)
SpineEditor
First-class

Built-in trace / replay

Lexical (engine layer)
Snapshots + history
SpineEditor
Per-stage trace tags

Framework coupling

Lexical (engine layer)
React-first
SpineEditor
Framework-neutral

Source language

Lexical (engine layer)
TypeScript
SpineEditor
TypeScript

License

Lexical (engine layer)
MIT
SpineEditor
MIT

Code: insert a paragraph

Lexical:

import { $createParagraphNode, $getRoot, $createTextNode } from "lexical";

editor.update(() => {
  const root = $getRoot();
  const paragraph = $createParagraphNode();
  paragraph.append($createTextNode("Hello"));
  root.append(paragraph);
});

SpineEditor:

import { branchNode, fragment, textNode } from "@spine-editor/core";

engine.dispatch({
  kind: "insertFragment",
  parentPath: [],
  index: engine.state.doc.root.children.length,
  fragment: fragment([
    branchNode("paragraph", [textNode("Hello")]),
  ]),
});

Choose Lexical if

  • You're building a React application and want a polished React API.
  • You want real-time collaboration via Yjs out of the box.
  • You want to render arbitrary React components inside the document via decorator nodes.
  • You want accessibility and performance validated at Meta scale.

Choose SpineEditor if

  • You want a focused engine, not an engine fused with a product framework.
  • You want every edit to produce an inspectable Plan artifact before mutation.
  • You need a framework-neutral mount with no React in the loop.
  • You need replayable, deterministic editing for testing or audit.