Read editor state, root state, annotations, selection geometry, and DOM-aware facts from React.
Create one component-owned editor. The optional dependency list controls when React creates a replacement editor.
Get the editor from the nearest EditorRoot provider. Use
useOptionalEditor() when a component may render outside a provider.
Get whether the editor is currently handling a composition session.
Get whether the editor is focused. Use this for toolbar UI, not for every rendered node in a large document.
Get whether the current editor is read-only.
Get the current editor selection. This hook re-renders when the selection changes, so keep it out of large rendered node trees.
Subscribe to a derived editor-state value. The selector runs inside
editor.read, so toolbar UI does not need to open a read boundary by
hand.
const isBold = useEditorState((state) => {
return state.marks()?.bold === true;
});const isBold = useEditorState((state) => {
return state.marks()?.bold === true;
});Use options.shouldUpdate to skip commits that cannot affect the selected
value.
const selection = useEditorState((state) => state.selection(), {
shouldUpdate: (change) => Boolean(change?.selectionChanged),
});const selection = useEditorState((state) => state.selection(), {
shouldUpdate: (change) => Boolean(change?.selectionChanged),
});Selectors always call the latest render's function, so they can close over component props without a dependency list.
const matchingText = useEditorState(
(state) => state.text.string([]).includes(query)
);const matchingText = useEditorState(
(state) => state.text.string([]).includes(query)
);Subscribe to editor state from an explicit editor instance. Use this for
toolbars, containers, or app chrome that receives an editor but is not rendered
inside that editor's EditorRoot provider.
const readOnly = useEditorRuntimeState(editor, (state) =>
state.view.isReadOnly()
);const readOnly = useEditorRuntimeState(editor, (state) =>
state.view.isReadOnly()
);Inside provider descendants, prefer useEditorState. It reads the same state
but gets the editor from context.
Commit subscriptions invalidate this selector synchronously. equalityFn and
shouldUpdate suppress unnecessary renders. Use a provider selector's explicit
deferred option when delayed delivery is an intentional product choice.
Subscribe to one defineStateField value.
const title = useStateFieldValue(documentTitle);const title = useStateFieldValue(documentTitle);The hook only re-renders when that field key appears in
change.dirtyStateKeys. Use it for document title, page settings, spellcheck,
and other document meta controls.
Create a setter for one defineStateField value.
const setTitle = useSetStateField(documentTitle);
setTitle("Q3 Launch Brief", { history: "new-batch", tags: "title-input" });const setTitle = useSetStateField(documentTitle);
setTitle("Q3 Launch Brief", { history: "new-batch", tags: "title-input" });The setter writes through editor.update and preserves DOM selection by
default. Pass the editor's typed update policy when the app needs history or
additional tags; the hook appends its selection-preservation tags.
Subscribe to a low-level derived editor value.
Use useEditorState for normal app-level editor reads. Use
useEditorSelector when you intentionally need the editor object or an
installed runtime API. Prefer node-, text-, decoration-, or element-scoped
hooks when rendering editor content.
const documentVersion = useEditorSelector(
(editor) => editor.read.runtime.snapshot().version,
{
equalityFn: Object.is,
shouldUpdate: (commit) =>
commit === undefined || commit.changed.has("document"),
}
);const documentVersion = useEditorSelector(
(editor) => editor.read.runtime.snapshot().version,
{
equalityFn: Object.is,
shouldUpdate: (commit) =>
commit === undefined || commit.changed.has("document"),
}
);Create undo/redo commands and keyboard handling for the active root.
const history = useEditorHistory();
return (
<button disabled={!history.canUndo} onClick={history.undo}>
Undo
</button>
);const history = useEditorHistory();
return (
<button disabled={!history.canUndo} onClick={history.undo}>
Undo
</button>
);Pass options.root to bind history controls to one root in the current provider. Pass options.editor to use an existing command view, including outside a Plate provider; omit root with an explicit editor. Explicit controls read the view’s current read-only permission and restore focus to that exact view. They cancel queued focus restoration when their target changes. Pass
focusPolicy: 'preserve' when undo/redo is controlled from external UI and
DOM focus should stay outside the editor. history.root is undefined for the
primary document and the root key for an extra root.
Use these when one editor owns multiple roots or external chrome.
Prefer useRootEditor(root) when UI knows its root. Use
useActiveEditor() only for UI that should follow the current selection.
Subscribe to whole-runtime editor state. The selector runs in a read boundary and re-renders only when the selected value changes.
Shared selector options are equalityFn, shouldUpdate, and deferred.
Selectors always read the latest render closure. Use shouldUpdate(commit)
with commit.changed to skip commits that cannot affect the selected value.
Subscribe to one root's state. The selector skips commits that cannot affect that root.
Read the extra root key that owns the current selection. It returns undefined
for the primary document.
Create a command-capable editor for one root.
Use this for root-specific toolbar or sidebar commands. Pass { readOnly: true } when the editor should only read state.
Omit root for the primary document.
Create a command-capable editor for the root that owns the selection.
Create root chrome props for mouse interaction outside the editable content, such as margin clicks and drag selection around a root.
const chrome = useRootChrome("body");
return <div {...chrome.props}>{children}</div>;const chrome = useRootChrome("body");
return <div {...chrome.props}>{children}</div>;Pass selection: 'end' for chrome that should place the caret at the end of a
root when clicked.
Resolve a schema-owned child content root and its chrome controller.
Use this inside an element renderer for editable voids or nested editor surfaces.
Resolve the stable child-root key for an element and slot.
Prefer persisted childRoots[slot] when the child root is part of document
data. The runtime fallback is for ephemeral editor islands.
Use these inside rendered editor content or node-local UI.
Get the current element object inside an element renderer.
Subscribe to the current path of the rendered element. Use this only for UI
that displays or derives live path state during render. Event handlers should
usually call editor.api.dom.resolvePath(element) and return early when it is
not mounted.
Subscribe to whether the current element, or an explicit element path,
matches the current selection. The default intersects mode includes text
selection inside the element. Use { mode: 'collapsed' } for a collapsed
selection and { mode: 'node' } only when the selection is a NodeSelection
whose path exactly matches the element. Node-focused asset rings and toolbars
should use node; caption or descendant editing UI should use intersects.
Pass { at: path } to watch an explicit path.
type UseElementSelectedOptions = {
at?: Path | null;
mode?: "intersects" | "collapsed" | "node";
};type UseElementSelectedOptions = {
at?: Path | null;
mode?: "intersects" | "collapsed" | "node";
};Subscribe to a value derived from one mounted node.
Pass options.nodeKey to target a specific node, or call it inside an editor
node renderer to use that renderer's runtime target.
Subscribe to a value derived from one mounted text node.
Pass options.nodeKey to target a specific text node, or call it inside an
editor text renderer to use that renderer's runtime target.
Use annotation hooks for durable anchored ranges such as comments, diagnostics, and external review markers.
Create an annotation store for durable anchored ranges such as comments, diagnostics, or external review markers.
Wrap reader components in AnnotationProvider when they should use the
store by default.
Pass the current annotation array directly. A new array identity refreshes the
store automatically. Use revision only for an external mutable source that
changes without producing a new array.
const annotations = comments.map((comment) => ({
anchor: comment.anchor,
data: comment,
id: comment.id,
}));
const annotationStore = useAnnotationStore(editor, annotations);
const externalStore = useAnnotationStore(editor, mutableAnnotations, {
revision: mutableAnnotationsRevision,
});const annotations = comments.map((comment) => ({
anchor: comment.anchor,
data: comment,
id: comment.id,
}));
const annotationStore = useAnnotationStore(editor, annotations);
const externalStore = useAnnotationStore(editor, mutableAnnotations, {
revision: mutableAnnotationsRevision,
});Read the current annotation snapshot. Without an explicit store, the hook reads
the store from the nearest AnnotationProvider.
Read one annotation by id.
Read immutable viewport rectangles for the current selection in one mounted
EditorContent. Pass the exact editableRef from the render slot. The hook
returns null during server rendering or when the ref is unmounted, belongs to
another editor, or has no native selection range.
const geometry = useSelectionGeometry({ editableRef });
const referenceRect = geometry?.boundingRect ?? null;const geometry = useSelectionGeometry({ editableRef });
const referenceRect = geometry?.boundingRect ?? null;RangeGeometry contains boundingRect, focusRect, and rects. Use
boundingRect to place a toolbar and focusRect to place a caret or label.
Every rectangle uses viewport coordinates.