docs/slate-v2/references/pr-description.md
Use this as the maintainer-facing PR body source. Keep it as a drift register: what belongs in the PR, why it belongs in v2, what proof exists, and what is not claimed yet.
The Slate v2 goal is not just "new architecture." The PR should close or
materially improve the highest-value issue clusters from
docs/slate-issues.
Full ledger:
Current summary:
36190630 open issues, 29 open PRs, 659 open
threads, and 617 gitcrawl clusters from the 2026-05-04 refresh. This is
corpus accounting, not an auto-close claim.149 frozen R7 input-runtime rows reviewed;
44 long-form proof-route rows, 59 matrix-only future-proof rows, 20
matrix-only non-claim rows, 3 matrix backfills, and 4 drift rows aligned
down to related.0.4 related/non-claim rows from the
processing backlog: #5894, #4730, #3387, and #3872. New exact fixed
or improved claims from that sync: 0.#5771 from Related to Improves,
with no new exact fixed issue claim.#3586 and
#4681, and refreshes #3568, #5181, and #4317. New exact fixed or
improved claims from that sync: 0.Editable render* and browser event props,
model/runtime behavior stays in extensions, and Plate owns renderer/keymap
product packaging. New exact fixed or improved claims from that sync: 0.transforms.* middleware rather than raw
Editable onKeyDown key branches. New exact fixed or improved claims from
that sync: 0.transforms.insertText, removes example-side Android flush plumbing, and
routes Android pending-diff timing to the input runtime. Focused unit,
typecheck, lint, and markdown-shortcuts browser proof passed; raw Android
device proof is still required before any exact #4532 claim. New exact
fixed or improved claims from that sync: 0.editable-island, rich editable island content should use same-runtime child
roots, scalar document-owned fields should use state fields, and
renderVoid stays content-only. New exact fixed or improved claims from that
sync: 0.editable-island for mixed native/app controls with optional child roots,
and adds the public API/lifecycle baseline for pure editor-flow child content:
EditorElementSpec.contentRoot, tx.roots.create/replace/delete, and
useSlateContentRoot. Keyboard projection, root payload remap, browser
proof, and release-gate verification remain unclaimed. New exact fixed or
improved claims from that sync: 0.Current fixed issue claims:
initialValue; editor state is seeded during editor creation.initialValue requirement.<Slate editor> changes.insertData docs state handler ordering, return semantics,
and fallback behavior.moveNodes commit restores the original tree and
selection.deleteFragment reselects the restored fragment.insertFragment(..., { at }) writes at the supplied target
instead of ambient selection.insertFragment into an empty text block leaves selection after
the inserted content.state.nodes.entries({ reverse: true }) returns the exact reverse
of the forward matched entry order for nested matching entries.useElementSelected() does not throw when a selected rendered
element removes itself, and useElementSelected({ at: path }) returns
false after the watched path is removed.*Api, so importing Slate
helpers no longer shadows DOM globals such as Node.Rules:
Fixes #....: <description> lines and count summaries in
this accounting section.Affected:
package.jsonbun.lockbunfig.tomlturbo.jsonbiome.jsoneslint.config.mjstsconfig*.jsonplaywright.config.tssite/**Accepted current shape:
Why it belongs in the PR:
Proof references:
.tmp/slate-v2/package.json.tmp/slate-v2/bunfig.toml.tmp/slate-v2/playwright.config.tsdocs/slate-v2/master-roadmap.mddocs/slate-v2/release-readiness-decision.mdAffected:
.tmp/slate-v2/packages/*/package.json.tmp/slate-v2/packages/*/tsconfig*.json.tmp/slate-v2/packages/*/src/index.tsAccepted current shape:
slate-layout extracts leaf-level layout runs with block offsets and Slate
leaf paths while preserving the existing block text fallback. Page projection
exposes placed runs, visual text rects, native hit rects, decoration ranges,
and generic block-local box metadata.slate-layout directly: geometry, projection, decorations, line hit rects,
page frames, and mixed Markdown-shaped content stay in the example as proof,
not as app-owned projection math.slate-layout should become the generic derived
layout service for continuous and paged snapshots, with a built-in Pretext
engine behind an internal boundary and slate-react consuming layout through
a DOM materialization policy instead of treating pagination or virtualization
as product rendering modes.pageView
groups page display settings, virtualized domStrategy drives internal
page/spread mounting in PagedEditable, measurementProfile is snapshot
metadata, pageBreaks is opt-in strict-fidelity metadata, and table/media
pagination uses generic provider/split protocols rather than a raw Slate
product TableKit. This planning target adds no fixed/improved issue claim.Why it belongs in the PR:
Proof references:
docs/slate-v2/final-api-hard-cuts-status.mddocs/slate-v2/references/live-shape-register.mddocs/slate-v2/replacement-gates-scoreboard.md.tmp/slate-v2/packages/slate-layout/test/page-layout-contract.test.ts.tmp/slate-v2/site/examples/ts/pagination.tsx.tmp/slate-v2/playwright/integration/examples/pagination.test.tsAffected:
.tmp/slate-v2/packages/slate/src/**.tmp/slate-v2/packages/slate/test/**docs/slate-v2/ledgers/slate-editor-api.mddocs/plans/2026-05-03-slate-v2-core-editor-method-hard-cut-ralplan.mdAccepted current shape:
editor.read is the read boundary.editor.update is the write boundary.editor, state, and tx groups.EditorCommit is the post-commit truth object for subscribers and integration
layers.Editor.* static method namespace is not the v2 teaching or
extension surface.*Api names such as NodeApi, ElementApi,
PathApi, and RangeApi; model type names stay Node, Element, Path,
and Range.extensions, not public
with* wrappers, withEditor, or author-facing editor.extend.history(),
dom(), and react().editableVoid(), checklist(), mention(), or table(). Plural names
are reserved for naturally plural domains such as shortcuts() or
normalizers(). PascalCase NameExtension is reserved for static extension
values. Plate's NamePlugin suffix belongs to Plate's product plugin layer,
not raw Slate extensions.editor.read((state) => state.<group>);
replayable extension writes/actions live under
editor.update((tx) => tx.<group>).editor.api.<capability>, so
history controls use editor.api.history, DOM/React runtime APIs use
editor.api.dom / editor.api.react, clipboard APIs use
editor.api.clipboard, and public editor-bound helper namespaces such as
HistoryEditor, DOMEditor, and a runtime ReactEditor namespace are not
app-facing APIs. The app-facing React editor instance type is the generic
extension-derived ReactEditor<Value, Extensions>.dom() installs the
DOM projection/focus handle and may also install the clipboard handle. Public
API keys are capability names, not package names.editor.getApi(extensionToken) where the
token is the branded factory or static extension value. String lookup such as
editor.getApi('history') and fresh-instance lookup such as
editor.getApi(history()) are not public APIs.editor.getApi('history'), editor.getApi(history()),
editor.api.history.undo, and editor.getApi(history).undo.state.nodes.entries(...) for lazy all-match
traversal, state.nodes.find(...) for first-match reads, and
state.nodes.some(...) for boolean active checks. Use
state.nodes.toArray(options, map?) only when a read or update callback needs
an explicit materialized array.void: 'block',
void: 'inline', void: 'markable-inline', or
void: 'editable-island'. Absence means non-void; void: true is fixture
data only when a matcher maps it to an explicit schema spec.apply extension points, direct onChange
extension points, and Transforms.* teaching are outside the final public
posture.Why it belongs in the PR:
Open debt:
Editor.replace. Treat that
as fixture migration debt, not a public API endorsement.void: true.
Treat those as fixture data matched into explicit string specs, not supported
EditorElementSpec.void config.defineStateField, canonical
Value = { roots, state? }, InitialValue normalization,
state.getField, tx.setField, root-explicit operations, root-aware
Point/Range, createEditorRuntime, createEditorView,
statePatches, dirtyStateKeys, the 'state' source,
useStateFieldValue, and useSetStateField, with comments external by
default. Do not add fixed or improved issue counts for this target until the
core/root/history/collab/react contracts in
docs/plans/2026-05-20-slate-v2-non-node-editor-state-architecture-ralplan.md
pass in .tmp/slate-v2. Current execution proof covers the first nine
vertical slices: createEditor accepts legacy children, { children, state },
and { roots, state } initialValue shapes and exposes canonical rooted
state.value.get() output; committed content operations include
root: 'main', Path stays numeric/root-local, and Point/Range transforms
ignore operations from other roots; createEditorRuntime owns the shared
editor value while createEditorView creates root-bound read/update facades
with view-local root, focus, and read-only policy; defineStateField
installs persisted descriptors with initial values and state.getField;
tx.setField emits operation-free statePatches, dirtyStateKeys, and the
'state' commit source, with a guard for large shared/history fields that
omit patch hooks; slate-history stores state patches in history batches and
undoes/redoes title changes as operation-free historic commits; collaboration
adapters can import shared state patches through tx.statePatches.replay and
export only collab: 'shared' patches through
Editor.getCollabStatePatches; React exposes useStateFieldValue and
useSetStateField, with field subscriptions filtered by dirtyStateKeys;
the examples app has a browser-proven Document State route that edits
document title/settings through state fields, keeps body content separate,
undoes/redoes state patches, and imports a remote title patch. Current
focused performance/release proof covers editor-store, history-retained
memory, collab-readiness, React rerender-breadth, and root bun check; two
field/root-specific benchmark script names remain missing harness coverage,
not passed proof. The multi-root React DX target is one canonical
<Slate editor={editor}> provider with multiple <Editable root="...">
surfaces. SlateRuntime, <Slate root="...">, createEditorView,
useSlateRuntimeState, and useSlateViewState remain advanced substrate
APIs for custom hosts. This is a non-claim API target for multi-root/header-
footer examples, not an added issue count. A follow-up non-claim API target
adds package-owned useSlateHistory and useSlateRootChrome so the canonical
example does not teach app-owned history shortcut parsing, stack reads,
selection metadata, active-root command routing, or RAF focus repair.isIsolating schema
policy into collapsed Backspace and direct mergeNodes; split-specific
closure remains unclaimed. #5972 is fixed by core delete target planning and
the inlines example browser proof. #5977 is fixed by internal editor
detection proof, DOM path lookup proof, and fail-closed unknown replay.
#3964/#3973/#4357/#3499 are fixed by core/history package regression proof.
#4195/#3841/#5629/#4648 remain
related/non-claim rows without exact browser or punctuation-policy proof.
#5412/#5429 are fixed by core insertFragment package proof for explicit
target insertion and empty-block caret placement. #5089 is fixed by package
and DOM clipboard proof for middle-paragraph multi-block fragment insertion.
#5080 is fixed by core package proof for exact reverse matched traversal.
#5684/#5028/#3885 remain related or non-claim rows.isIsolating policy blocks collapsed Backspace and
direct mergeNodes across protected containers; split-specific closure remains
unclaimed.Operation exposes concrete built-in operation subtype guards
with runtime and TypeScript narrowing proof.Proof references:
docs/slate-v2/references/architecture-contract.mddocs/slate-v2/absolute-architecture-release-claim.mddocs/slate-v2/final-api-hard-cuts-status.mddocs/plans/2026-05-03-slate-v2-core-editor-method-hard-cut-ralplan.mddocs/plans/2026-05-07-slate-v2-core-structural-delete-normalization-ralplan.mddocs/plans/2026-05-07-slate-v2-inline-delete-boundary-repro-ralplan.mddocs/plans/2026-05-07-slate-v2-operation-extensibility-validation-ralplan.mddocs/plans/2026-05-07-slate-v2-insert-fragment-at-location-ralplan.mddocs/plans/2026-05-13-slate-v2-void-kind-api-ralplan.mddocs/plans/2026-05-20-slate-v2-non-node-editor-state-architecture-ralplan.md.tmp/completion-checks/slate-v2-insert-fragment-at-location-execution.md.tmp/slate-v2/packages/slate/test/public-element-void-kind-contract.ts.tmp/slate-v2/packages/slate/test/schema-contract.ts.tmp/slate-v2/packages/slate/test/clipboard-contract.ts.tmp/slate-v2/packages/slate/test/query-contract.ts.tmp/slate-v2/packages/slate/test/collab-history-runtime-contract.ts.tmp/slate-v2/packages/slate/test/commit-metadata-contract.ts.tmp/slate-v2/packages/slate/test/migration-backbone-contract.ts.tmp/slate-v2/packages/slate/src/editor/nodes.ts.tmp/completion-checks/slate-v2-editor-nodes-reverse-order-ralplan.md.tmp/completion-checks/slate-v2-core-structural-delete-normalization-execution.md.tmp/completion-checks/slate-v2-operation-extensibility-validation-execution.md.tmp/completion-checks/slate-v2-core-caret-movement-word-insert-break-execution.md.tmp/slate-v2/packages/slate/test/snapshot-contract.ts.tmp/slate-v2/packages/slate/test/transaction-contract.tsAffected:
.tmp/slate-v2/packages/slate-history/**.tmp/slate-v2/packages/slate-hyperscript/**Accepted current shape:
slate-history follows the transaction/commit model instead of patching
mutable editor internals.slate-hyperscript exists as a v2 fixture/test authoring helper, not a
compatibility sink for stale core assumptions.Why it belongs in the PR:
Proof references:
docs/slate-v2/master-roadmap.mddocs/slate-v2/replacement-gates-scoreboard.mddocs/slate-v2/references/normalization-reference.mdAffected:
.tmp/slate-v2/packages/slate-dom/src/**.tmp/slate-v2/packages/slate-dom/test/**Accepted current shape:
slate-dom owns DOM selection export/import, clipboard policy, DOM coverage
lookup, and hotkey matching.resolve* helpers return null for recoverable model/DOM projection
gaps.slate-react uses resolver helpers instead of
suppressThrow, local catch wrappers, or strict projection calls.is-hotkey is not a dependency. Slate owns isHotkey(spec, event) in
slate-dom.Why it belongs in the PR:
Proof references:
docs/plans/2026-05-03-slate-v2-hotkey-runtime-dependency-ralplan.mddocs/plans/2026-05-02-slate-v2-hidden-subtree-first-class-ralplan.mddocs/plans/2026-05-03-slate-v2-dom-present-large-doc-phase-6-plan.mddocs/plans/2026-05-14-slate-v2-total-runtime-error-policy-ralplan.mddocs/slate-v2/replacement-gates-scoreboard.mdAffected:
.tmp/slate-v2/packages/slate/src/**.tmp/slate-v2/packages/slate-dom/src/plugin/dom-clipboard-runtime.ts.tmp/slate-v2/packages/slate-react/src/editable/clipboard-input-strategy.ts.tmp/slate-v2/packages/slate-dom/test/clipboard-boundary.ts.tmp/slate-v2/packages/slate/test/clipboard-contract.tsAccepted current shape:
slate owns fragment extraction and insertion semantics.slate-dom owns DataTransfer, custom fragment MIME keys, keyed embedded
HTML fragment transport, plain-text fallback, and DOM coverage copy/paste
policy.slate-react owns browser event dispatch for copy, cut, paste, drag, and
drop, then delegates payload work to editor.api.clipboard.editor.api.clipboard; raw
editor does not grow a public clipboard namespace.insertData stays input-only and does not own output
serialization or product paste-rule policy.application/${clipboardFormatKey}
payloads and embedded data-slate-fragment HTML fallback. Mismatched
embedded fragments fall back to safe import behavior instead of importing
schema-private JSON.dom({ clipboardFormatKey: 'x-product-fragment' }) in the editor
extensions list.DOMClipboardInsertDataHandler is public from slate-dom; app-owned rich
HTML/image paste behavior runs through typed clipboard ingress authoring.replace_children through
tx.operations.replay(...); CRDT/Yjs-style adapters lower it at their own
boundary if their transport cannot represent child-window replacement
atomically.list-item.data-slate-fragment, invalid JSON, URI-decode failures,
non-array JSON, no-fallback no-op behavior, and rich fragment target-block
preservation, custom-key embedded HTML acceptance/rejection, plus selected
inline void copy/paste/cut ordering and selected block void cut repair.Performance status:
replace_children operation in the issue-size benchmark. Exact
Fixes #5945 closure still needs a 10,000-line browser artifact for the
plaintext example flow.49.35ms for copying
10,000 populated blocks and 235.22ms for pasting 10,000 plaintext lines
into a 10,000-block populated editor with one logical operation. Exact
Fixes #4056 closure still needs the historical browser repro.replace_children operation. The latest
issue-size run reports warm edit p50 9.95ms, warm copy-plus-delete p50
8.62ms, and operation count 1; the cold snapshot row remains visible at
p50 171.91ms. Browser stress covers a 5,000-block huge-document cut row.
Exact Fixes #5992 closure still needs maintainer acceptance that the
benchmark plus browser stress matches the original repro.Why it belongs in the PR:
Proof references:
docs/plans/2026-05-04-slate-v2-clawsweeper-v2-clipboard-serialization-ralplan.md.tmp/slate-v2/tmp/slate-clipboard-large-payload-benchmark.json.tmp/slate-v2/packages/slate-dom/src/plugin/dom-clipboard-runtime.ts.tmp/slate-v2/packages/slate/src/transforms-text/insert-fragment.ts.tmp/slate-v2/packages/slate-dom/test/clipboard-boundary.ts.tmp/slate-v2/packages/slate/test/clipboard-contract.ts.tmp/completion-checks/slate-v2-multiblock-fragment-middle-insert-execution.md.tmp/slate-v2/packages/slate-react/src/editable/clipboard-input-strategy.ts.tmp/completion-checks/slate-v2-clawsweeper-v2-clipboard-serialization-execution.md.tmp/completion-checks/slate-v2-clawsweeper-v2-clipboard-fragment-insertion-shape-execution.md.tmp/completion-checks/slate-v2-clawsweeper-v2-clipboard-inline-void-execution.md.tmp/completion-checks/slate-v2-clawsweeper-v2-clipboard-structural-cut-delete-execution.md.tmp/completion-checks/slate-v2-clawsweeper-v2-clipboard-api-extension-surface-execution.mdAffected:
.tmp/slate-v2/packages/slate-react/src/**.tmp/slate-v2/site/examples/**.tmp/slate-v2/tests/integration/**Accepted current shape:
EditorSelectorOptions<TEditor> for useEditorSelector.decorate stays the simple transient range API.decorationSources and createDecorationSource are the scalable path for
external or high-churn overlays.Why it belongs in the PR:
Proof references:
docs/slate-v2/master-roadmap.mddocs/slate-v2/replacement-gates-scoreboard.mddocs/slate-v2/final-api-hard-cuts-status.mddocs/slate-v2/absolute-architecture-release-claim.mddocs/plans/2026-05-08-slate-v2-react-decorations-slate-issues-ralplan.md.tmp/slate-v2/packages/slate-react/test/generic-react-editor-contract.tsx.tmp/slate-v2/packages/slate-react/test/provider-hooks-contract.tsx.tmp/slate-v2/packages/slate-react/test/projections-and-selection-contract.tsx.tmp/slate-v2/packages/slate-react/test/app-owned-customization.tsx.tmp/slate-v2/packages/slate-react/test/surface-contract.tsx.tmp/slate-v2/packages/slate-react/test/keyboard-input-strategy-contract.test.ts.tmp/slate-v2/packages/slate-react/test/annotation-store-contract.test.tsx.tmp/slate-v2/packages/slate-react/test/widget-layer-contract.test.tsx.tmp/slate-v2/docs/libraries/slate-react/editable.md.tmp/slate-v2/docs/libraries/slate-react/hooks.md.tmp/slate-v2/docs/libraries/slate-react/slate.md.tmp/slate-v2/packages/slate-react/test/editing-kernel-contract.ts.tmp/slate-v2/packages/slate-react/test/editing-epoch-kernel-contract.ts.tmp/slate-v2/packages/slate-react/test/selection-runtime-contract.test.ts.tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts.tmp/slate-v2/packages/slate-react/test/rendering-strategy-and-scroll.test.tsx.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.tmp/slate-v2/playwright/integration/examples/placeholder.test.ts.tmp/slate-v2/playwright/integration/examples/inlines.test.ts.tmp/slate-v2/playwright/integration/examples/mentions.test.ts.tmp/slate-v2/playwright/integration/examples/highlighted-text.test.ts.tmp/slate-v2/playwright/integration/examples/markdown-shortcuts.test.ts.tmp/slate-v2/scripts/benchmarks/browser/react/rerender-breadth.tsx.tmp/slate-v2/scripts/benchmarks/browser/react/huge-document-overlays.tsxAffected:
.tmp/slate-v2/packages/slate/src/create-editor.ts.tmp/slate-v2/packages/slate/src/core/public-state.ts.tmp/slate-v2/packages/slate-react/src/hooks/use-slate-editor.ts.tmp/slate-v2/packages/slate-react/src/components/slate.tsx.tmp/slate-v2/site/examples/ts/**docs/plans/2026-05-04-slate-v2-react-editor-initialization-value-ralplan.mdAccepted current shape:
createEditor({ initialValue, initialSelection }) seeds public editor state
synchronously before React provider render.useSlateEditor({ initialValue, extensions }) is the React helper for
creation-time extension composition.createReactEditor({ initialValue, extensions }) constructor can
support tests and non-hook React setup without introducing a second
composition model.<Slate editor={editor}> provides context, subscriptions, decoration sources,
one annotation store, and callbacks. It does not initialize document content.editor.update((tx) => tx.value.replace({ children, selection })).initialValue: [] fails with a clear core error instead of
booting a broken editor.Why it belongs in the PR:
Issue coverage:
Proof references:
docs/plans/2026-05-04-slate-v2-react-editor-initialization-value-ralplan.mddocs/slate-v2/ledgers/issue-coverage-matrix.md.tmp/slate-v2/packages/slate/test/state-tx-public-api-contract.ts.tmp/slate-v2/packages/slate-react/test/provider-hooks-contract.tsx.tmp/slate-v2/packages/slate-react/test/surface-contract.tsx.tmp/slate-v2/packages/slate-react/test/generic-react-editor-contract.tsxAffected:
.tmp/slate-v2/packages/slate/src/core/editor-extension.ts.tmp/slate-v2/packages/slate/src/core/transform-middleware.ts.tmp/slate-v2/packages/slate/src/create-editor.ts.tmp/slate-v2/packages/slate/src/interfaces/editor.ts.tmp/slate-v2/packages/slate/test/extension-methods-contract.ts.tmp/slate-v2/packages/slate/test/generic-extension-namespace-contract.ts.tmp/slate-v2/packages/slate-react/src/editable/editable-input-rules.ts.tmp/slate-v2/packages/slate-react/src/editable/runtime-root-engine.ts.tmp/slate-v2/packages/slate-react/src/index.ts.tmp/slate-v2/packages/slate-react/src/components/editable.tsx.tmp/slate-v2/packages/slate-react/src/components/editable-text-blocks.tsx.tmp/slate-v2/site/examples/ts/check-lists.tsx.tmp/slate-v2/site/examples/ts/markdown-shortcuts.tsx.tmp/slate-v2/site/examples/ts/inlines.tsxdocs/plans/2026-05-04-slate-v2-legacy-example-dx-ralplan.mddocs/plans/2026-05-13-slate-v2-editable-input-rule-ownership-ralplan.mdCurrent implemented shape:
slate extension registration accepts transform middleware for every public
mutating editor transform in EditorTransformApi except engine controls.bookmark, normalize,
setNormalizing, and withoutNormalizing.next() forwards current args unchanged, and next(overrides) shallow-merges
explicit overrides such as next({ text: normalizedText }).next(), matching Slate's old
withX(editor) override feel without monkeypatching editor methods.deleteBackward -> delete do not double-fire extension hooks.EditableInputRule*, editableInputRules(...),
EDITABLE_INPUT_RULE_CAPABILITY, or an Editable inputRules prop.onDOMBeforeInput as the public raw native escape hatch. Public
onCommand / EditableCommand* is cut; native-format behavior that Slate
owns stays internal/runtime-owned and covered by focused contracts.transforms.deleteBackward(...).transforms.insertText(...) where the behavior is model-owned.commands fields remain rejected; direct
Editor.registerCommand(...) stays the low-level substrate and advanced
escape hatch, while normal examples teach transform middleware.Accepted current source shape:
extension.queries covers accepted pure read methods across
fragment, marks, nodes, points, ranges, and text, including
static/read parity for the pure read keys that do not naturally fit the
previous grouped state view: nodes.path, nodes.elementReadOnly,
nodes.shouldMergeNodesRemovePrevNode, and points.positions.next(overrides),
preserves generator reads during default delegation, rejects double next(),
and prevents editor.update from starting inside query middleware.normalizers.editor is the typed ordered middleware lane for editor-root and
value-level normalization.normalizers.node is the typed ordered middleware lane for non-root node
normalization, with next(overrides), built-in fallback delegation, cleanup,
extension-local registration ids, scoped normalizer tx, and double-next
proof.tx exposes model repair APIs and value.get(), but not
recursive normalization controls, operation replay, or whole-value
replacement.apply and onChange
pressure. The accepted author-facing naming target is operations.apply for
operation-level hooks, onCommit for post-transaction observers, and setup
for extension-local runtime installation.docs/plans/2026-05-13-slate-v2-editable-input-rule-ownership-ralplan.md
Section Full Editor Method Override Coverage Ralplan - 2026-05-16.Why it belongs in the PR:
inputType strings.withX(editor) override feel for public examples.next() contract keeps the common case tiny while still allowing
middleware to normalize args before delegating.Not claimed:
onKeyDown escape hatch.#3557; the insert-node/fragment extension pressure is related proof, not an
exact upstream repro closure.Proof references:
.tmp/slate-v2/packages/slate/src/core/editor-extension.ts.tmp/slate-v2/packages/slate/src/core/transform-middleware.ts.tmp/slate-v2/packages/slate/src/core/query-middleware.ts.tmp/slate-v2/packages/slate/src/core/normalize-node.ts.tmp/slate-v2/packages/slate/src/create-editor.ts.tmp/slate-v2/packages/slate/src/interfaces/editor.ts.tmp/slate-v2/packages/slate/src/core/command-registry.ts.tmp/slate-v2/packages/slate/src/editor/delete-backward.ts.tmp/slate-v2/packages/slate/test/query-extension-contract.ts.tmp/slate-v2/packages/slate/test/normalization-contract.ts.tmp/slate-v2/packages/slate/test/apply-onchange-hard-cut-contract.ts.tmp/slate-v2/packages/slate/test/extension-methods-contract.ts.tmp/slate-v2/packages/slate/test/generic-extension-namespace-contract.ts.tmp/slate-v2/packages/slate/test/transaction-contract.ts.tmp/slate-v2/packages/slate/test/transforms-contract.ts.tmp/slate-v2/packages/slate/test/public-surface-contract.ts.tmp/slate-v2/site/examples/ts/forced-layout.tsx.tmp/slate-v2/scripts/benchmarks/core/compare/normalization.mjs.tmp/slate-v2/packages/slate-react/src/components/editable.tsx.tmp/slate-v2/packages/slate-react/src/editable/runtime-root-engine.ts.tmp/slate-v2/site/examples/ts/check-lists.tsx.tmp/slate-v2/site/examples/ts/markdown-shortcuts.tsx.tmp/slate-v2/site/examples/ts/inlines.tsxbun check in .tmp/slate-v2PLAYWRIGHT_RETRIES=0 PLAYWRIGHT_WORKERS=1 bun x playwright test playwright/integration/examples/forced-layout.test.ts --project=chromiumPLAYWRIGHT_RETRIES=0 PLAYWRIGHT_WORKERS=1 bun x playwright test playwright/integration/examples/check-lists.test.ts playwright/integration/examples/markdown-shortcuts.test.ts playwright/integration/examples/inlines.test.ts --project=chromiumdocs/plans/2026-05-13-slate-v2-editable-input-rule-ownership-ralplan.mdAffected:
.tmp/slate-v2/packages/slate-react/src/components/editable.tsx.tmp/slate-v2/packages/slate-react/src/editable/editable-key-commands.ts.tmp/slate-v2/packages/slate-react/src/editable/keyboard-input-strategy.ts.tmp/slate-v2/packages/slate-react/src/editable/runtime-before-input-events.ts.tmp/slate-v2/packages/slate-react/src/editable/input-router.ts.tmp/slate-v2/site/examples/ts/code-highlighting.tsx.tmp/slate-v2/site/examples/ts/iframe.tsx.tmp/slate-v2/site/examples/ts/images.tsx.tmp/slate-v2/site/examples/ts/markdown-shortcuts.tsx.tmp/slate-v2/site/examples/ts/richtext.tsx.tmp/slate-v2/site/examples/ts/tables.tsx.tmp/slate-v2/site/examples/ts/hovering-toolbar.tsx.tmp/slate-v2/docs/libraries/slate-react/editable.mddocs/plans/2026-05-14-slate-v2-callback-memoization-dx-ralplan.mdAccepted current shape:
onDOMBeforeInput is the raw native InputEvent escape hatch and receives
Slate context.onCommand and EditableCommand* are no longer accepted raw Slate
app DX. They crossed into product command language.Editable onKeyDown for UI hotkeys and
transforms.* middleware for reusable model behavior.useMemo or useCallback.Why it belongs in the PR:
inputType parsing as normal
editor behavior, but raw Slate also should not expose product command unions
as public app API.onDOMBeforeInput only when they need a low-level escape hatch.Not claimed:
onDOMBeforeInput paste behavior.Proof references:
.tmp/slate-v2/packages/slate-react/test/editing-kernel-contract.ts.tmp/slate-v2/packages/slate-react/test/editable-behavior.tsx.tmp/slate-v2/packages/slate-react/test/input-router-contract.test.tsx.tmp/slate-v2/packages/slate-react/test/keyboard-input-strategy-contract.test.ts.tmp/slate-v2/packages/slate-react/test/surface-contract.tsx.tmp/slate-v2/playwright/integration/examples/hovering-toolbar.test.tsdocs/slate-v2/ledgers/issue-coverage-matrix.mddocs/plans/2026-05-18-slate-v2-table-transform-boundary-ralplan.mdAffected:
.tmp/slate-v2/packages/slate/src/interfaces/text.ts.tmp/slate-v2/packages/slate/src/index.ts.tmp/slate-v2/packages/slate/test/generic-value-contract.ts.tmp/slate-v2/site/examples/ts/custom-types.d.ts.tmp/slate-v2/site/examples/ts/mark-utils.ts.tmp/slate-v2/site/examples/ts/richtext.tsx.tmp/slate-v2/site/examples/ts/hovering-toolbar.tsx.tmp/slate-v2/site/examples/ts/iframe.tsxdocs/plans/2026-05-16-slate-v2-boolean-mark-key-type-helper-ralplan.mdAccepted shape:
slate should export type-only BooleanMarkKeysOf<N> and
BooleanMarksOf<N> helpers derived from existing MarksOf<N>.BooleanTextKey<T> with BooleanMarkKeysOf<CustomText>.fontSize?: string.MarkKeysOf<N> keeps its existing optional-mark fallback behavior; this is an
additive helper, not a semantic rewrite.Why it belongs in the PR:
Not claimed:
Improves #5075.Proof references:
.tmp/slate-v2/packages/slate/src/interfaces/text.ts.tmp/slate-v2/packages/slate/test/generic-value-contract.ts.tmp/slate-v2/site/examples/ts/custom-types.d.ts.tmp/slate-v2/site/examples/ts/mark-utils.tsdocs/plans/2026-05-16-slate-v2-boolean-mark-key-type-helper-ralplan.mdAffected:
.tmp/slate-v2/packages/slate/src/interfaces/node.ts.tmp/slate-v2/packages/slate-react/src/hooks/use-slate-decoration-source.ts.tmp/slate-v2/packages/slate-react/src/decoration-source.ts.tmp/slate-v2/site/examples/ts/code-highlighting.tsx.tmp/slate-v2/site/examples/ts/search-highlighting.tsx.tmp/slate-v2/site/examples/ts/markdown-preview.tsx.tmp/slate-v2/site/examples/ts/highlighted-text.tsx.tmp/slate-v2/site/examples/ts/external-decoration-sources.tsx.tmp/slate-v2/site/examples/ts/rendering-strategy-runtime.tsxdocs/plans/2026-05-04-slate-v2-legacy-example-dx-ralplan.mddocs/plans/2026-05-18-slate-v2-search-highlighting-dx-ralplan.mdAccepted current shape:
createDecorationSource(editor, options) remains the low-level projection
source API.useSlateDecorationSource(editor, options) owns React lifecycle cleanup for
common example and app code.read and runtimeScope callbacks.deps?: readonly unknown[] so external query/state changes
refresh the source without recreating it or teaching memoized option objects
in examples.dirtiness and runtimeScope remain visible in the call site because they
are the performance contract.dirtiness: ['text', 'node']
without caller-side tuple constants.NodeApi.findTextRanges(root, query, options) is the accepted raw Slate
helper for turning text matches into Range[]. It is not a search feature:
first-tranche options stay thin with caseSensitive plus RegExp or matcher
callbacks, no wholeWord, no locale policy, and no public
across: 'text-siblings' option.createRangeDecorationSource(editor, options) is the accepted helper over
createDecorationSource for callers that already have ranges or range
entries and do not need to hand-build projection objects, keys, or refresh
defaults.useSlateRangeDecorationSource(editor, options) is the React helper for
range-based decorations. It shares the low-level hook's lifecycle cleanup and
deps refresh contract without recreating the source object.createDecorationSource and useSlateDecorationSource remain the power APIs
for external stores, custom invalidation, manual runtimeScope, and metrics.useEditorSelector plus
decorationSources; no useSlateSelector alias or direct
<Slate projectionStore={...}> prop is required.Why it belongs in the PR:
useMemo plus cleanup useEffect ceremony.editor.api.search, SearchApi, or product search
options to satisfy a search-highlighting example.Current proof:
bun run bench:react:huge-document-overlays:local passes in .tmp/slate-v2.sourceReadCount, recomputeCount, fullFallbackCount,
changedRuntimeBucketCount, runtimeSubscriberWakeCount, and
globalSubscriberWakeCount must not regress.#4076 stays a docs/example non-claim. It supports simplifying the example
and rejecting product-shaped search API in raw Slate; it is not a fixed or
improved issue claim.Proof references:
.tmp/slate-v2/packages/slate-react/test/app-owned-customization.tsx.tmp/slate-v2/packages/slate-react/test/projections-and-selection-contract.tsx.tmp/slate-v2/scripts/benchmarks/browser/react/huge-document-overlays.tsx.tmp/slate-v2/scripts/benchmarks/browser/react/rerender-breadth.tsx.tmp/slate-v2/site/examples/ts/code-highlighting.tsx.tmp/slate-v2/site/examples/ts/search-highlighting.tsx.tmp/slate-v2/site/examples/ts/markdown-preview.tsx.tmp/slate-v2/site/examples/ts/highlighted-text.tsx.tmp/slate-v2/site/examples/ts/external-decoration-sources.tsx.tmp/slate-v2/site/examples/ts/rendering-strategy-runtime.tsxdocs/plans/2026-05-04-slate-v2-legacy-example-dx-ralplan.mddocs/plans/2026-05-18-slate-v2-search-highlighting-dx-ralplan.mdAffected:
.tmp/slate-v2/packages/slate-react/src/components/slate.tsx.tmp/slate-v2/packages/slate-react/src/hooks/use-slate-annotations.tsx.tmp/slate-v2/packages/slate-react/src/hooks/use-slate-annotation-store.tsx.tmp/slate-v2/packages/slate-react/src/hooks/use-slate-widget-store.tsx.tmp/slate-v2/packages/slate-react/test/annotation-store-contract.tsx.tmp/slate-v2/packages/slate-react/test/widget-layer-contract.tsx.tmp/slate-v2/packages/slate-react/test/surface-contract.tsx.tmp/slate-v2/docs/libraries/slate-react/annotations.md.tmp/slate-v2/docs/libraries/slate-react/hooks.md.tmp/slate-v2/site/examples/ts/collaborative-comments.tsx.tmp/slate-v2/site/examples/ts/review-comments.tsx.tmp/slate-v2/site/examples/ts/persistent-annotation-anchors.tsxdocs/plans/2026-05-04-slate-v2-legacy-example-dx-ralplan.mdAccepted current shape:
<Slate annotationStore={store}> is singular because one annotation store
already owns many annotations.useSlateAnnotations() and useSlateAnnotation(id) read the provider store
by default.useSlateAnnotationStore and useSlateWidgetStore accept projector options
with explicit deps so examples can map product data without caller-side
useMemo arrays.Why it belongs in the PR:
<Slate> and component props
just to list annotations.Proof references:
.tmp/slate-v2/packages/slate-react/test/annotation-store-contract.tsx.tmp/slate-v2/packages/slate-react/test/widget-layer-contract.tsx.tmp/slate-v2/site/examples/ts/collaborative-comments.tsx.tmp/slate-v2/site/examples/ts/review-comments.tsx.tmp/slate-v2/site/examples/ts/persistent-annotation-anchors.tsxdocs/plans/2026-05-04-slate-v2-legacy-example-dx-ralplan.mdAffected:
.tmp/slate-v2/packages/slate-react/src/editable/editable-renderers.ts.tmp/slate-v2/packages/slate-react/src/components/editable-text-blocks.tsx.tmp/slate-v2/packages/slate-react/src/index.ts.tmp/slate-v2/docs/concepts/09-rendering.md.tmp/slate-v2/docs/libraries/slate-react/editable.md.tmp/slate-v2/docs/walkthroughs/03-defining-custom-elements.md.tmp/slate-v2/docs/walkthroughs/04-applying-custom-formatting.md.tmp/slate-v2/docs/walkthroughs/05-executing-commands.md.tmp/slate-v2/docs/walkthroughs/09-performance.mdAccepted current shape:
editableRenderers(...)
and any planned editable.renderers facet are hard cuts.Editable render props are the Slate React rendering API.useCallback cargo cult and not raw Slate renderer registries.slate stays non-React; renderer registration belongs to slate-react.Not claimed:
EditorElementSpec React renderer field.Proof references:
.tmp/slate-v2/packages/slate-react/test/surface-contract.test.tsx.tmp/slate-v2/packages/slate-react/src/editable/editable-renderers.ts.tmp/slate-v2/packages/slate-react/src/components/editable-text-blocks.tsxdocs/plans/2026-05-14-slate-v2-example-memoization-hard-cut-ralplan.mdAffected:
.tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts.tmp/slate-v2/packages/slate-dom/src/utils/weak-maps.ts.tmp/slate-v2/packages/slate-react/src/components/editable-text-blocks.tsx.tmp/slate-v2/packages/slate-react/src/hooks/use-element-path.ts.tmp/slate-v2/packages/slate-react/src/hooks/use-element-selected.ts.tmp/slate-v2/packages/slate-react/src/hooks/use-slate-node-ref.tsx.tmp/slate-v2/packages/slate-react/test/surface-contract.tsx.tmp/slate-v2/packages/slate-react/test/provider-hooks-contract.tsx.tmp/slate-v2/packages/slate-dom/test/bridge.ts.tmp/slate-v2/site/examples/ts/images.tsx.tmp/slate-v2/site/examples/ts/embeds.tsx.tmp/slate-v2/site/examples/ts/check-lists.tsx.tmp/slate-v2/site/examples/ts/paste-html.tsx.tmp/slate-v2/site/examples/ts/mentions.tsx.tmp/slate-v2/docs/libraries/slate-react/editable.md.tmp/slate-v2/docs/libraries/slate-react/hooks.mddocs/plans/2026-05-12-slate-v2-render-path-prop-performance-ralplan.mdAccepted current shape:
RenderElementProps receives attributes, children, element,
isInline, and slots; it does not expose eager path or index.RenderVoidProps receives { element }; it does not expose eager path.editor.api.dom.findPath(element).useElementPath() is the opt-in render-time path subscription.useElementSelected() keeps intersection semantics; block voids that only
want selected UI for a collapsed caret use
useElementSelected({ mode: 'collapsed' }).useElementSelected({ at: path }); there is no
positional path overload.target, path, or index compat alias is kept for v2 render
props.Why it belongs in the PR:
Proof references:
.tmp/slate-v2/packages/slate-react/test/surface-contract.tsx.tmp/slate-v2/packages/slate-react/test/use-element-selected.test.tsx.tmp/slate-v2/packages/slate-react/test/provider-hooks-contract.tsx.tmp/slate-v2/packages/slate-dom/test/bridge.ts.tmp/slate-v2/site/examples/ts/images.tsx.tmp/slate-v2/site/examples/ts/embeds.tsx.tmp/slate-v2/site/examples/ts/check-lists.tsx.tmp/slate-v2/site/examples/ts/paste-html.tsxdocs/plans/2026-05-12-slate-v2-render-path-prop-performance-ralplan.mdAffected:
.tmp/slate-v2/packages/slate-dom/src/plugin/dom-coverage.ts.tmp/slate-v2/packages/slate-dom/src/plugin/dom-clipboard-runtime.ts.tmp/slate-v2/packages/slate-react/src/dom-coverage-boundary.tsx.tmp/slate-v2/site/examples/ts/dom-coverage-boundaries.tsxdocs/plans/2026-05-02-slate-v2-hidden-subtree-first-class-ralplan.mdAccepted current shape:
HiddenRange and HiddenSelf
naming are rejected.Why it belongs in the PR:
Cannot resolve a Slate node from DOM node failure class
from becoming a permanent v2 footgun.Not claimed:
slots.Boundary.Proof references:
docs/plans/2026-05-02-slate-v2-hidden-subtree-first-class-ralplan.mddocs/plans/2026-05-03-slate-v2-dom-present-large-doc-phase-6-plan.mddocs/slate-v2/references/chunking-review.mdAffected:
.tmp/slate-v2/packages/slate-react/src/rendering-strategy/**.tmp/slate-v2/site/examples/ts/huge-document.tsx.tmp/slate-v2/site/examples/ts/rendering-strategy-runtime.tsx.tmp/slate-v2/site/examples/ts/rendering-strategy-virtualized.tsxdocs/plans/2026-05-03-slate-v2-dom-present-large-doc-phase-6-plan.mddocs/plans/2026-05-03-slate-v2-experimental-virtualized-rendering-boundary.mdAccepted current shape:
interactiveReady and nativeSurfaceComplete are separate concepts.{ type: 'virtualized' }; stable string strategies stay
auto, full, and staged. Public shell / preview-shell is cut before
beta; preview or collapse UI belongs above Slate and must use DOM coverage.Editable, so examples do not need caller-side useMemo just to stabilize
option identity.Why it belongs in the PR:
Open gates:
renderingStrategy to
domStrategy before beta because the current name conflates layout,
pagination, preview surfaces, and viewport virtualization. Any temporary
alias is implementation-only and must not appear in public examples or docs.Proof references:
docs/slate-v2/references/chunking-review.mddocs/plans/2026-05-03-slate-v2-dom-present-large-doc-phase-6-plan.mddocs/plans/2026-05-03-slate-v2-experimental-virtualized-rendering-boundary.mddocs/plans/2026-05-23-slate-v2-large-document-performance-virtualization-ralplan.mddocs/slate-v2/replacement-gates-scoreboard.md.tmp/slate-v2/packages/slate-react/test/surface-contract.test.tsx.tmp/slate-v2/site/examples/ts/rendering-strategy-runtime.tsxAffected:
.tmp/slate-v2/site/constants/examples.ts.tmp/slate-v2/site/pages/examples/[example].tsx.tmp/slate-v2/site/examples/**.tmp/slate-v2/tests/integration/**Accepted current shape:
Experimental Virtualized Rendering.Why it belongs in the PR:
Proof references:
docs/plans/2026-05-03-slate-v2-mentions-void-arrow-selection-regression.mddocs/plans/2026-05-03-slate-v2-experimental-virtualized-rendering-boundary.mddocs/slate-v2/replacement-gates-scoreboard.mdDo not write the PR as release-ready until these are closed or explicitly scoped out:
bun test:integration-local closure.Review rule: