Plate
PlateEditorsTemplates
GitHub16kGitHub
DiscordDiscord
  • Plate
  • Editor API
  • Editor Transforms
  • Node
  • Element
  • Text
  • Path
  • Point
  • Range
  • Location
  • Anchor
  • Selection
  • Document Change
  • DOM API
  • React Hooks
  • Plate Core
    • Plate Components
    • Plate Editor
    • Plate Plugin
    • Editor Context
    • Plate Controller
  • Plate Utils
  • Resizable

Editor Context

PreviousNext

Read editor, plugin, and focus state with Plate React hooks.

Import Plate state hooks from platejs/react. Use editor hooks for document state, usePluginStore for plugin state, and event hooks for focus history.

Editor state

Render editor hooks below EditorRoot, or below a EditorController that connects shared UI to its editors.

HookReturns
useEditor()The matching editor; throws when no editor is active.
useOptionalEditor()
Plate PluginPlate Controller

On This Page

Editor stateContainer and lifetimePlugin stateFocus historyExplicit editors
Build your editor
Production-ready AI template and reusable components.
Get all-access
The matching editor, or null while its controller has no matching editor.
useEditorId()The resolved editor's ID.
useEditorMounted()Whether the editor's editable surface is mounted.
useEditorSelection()The current selected-root range, or null.
useEditorHasSelection()Whether a selected-root text selection exists, including a caret. Rerenders only when presence changes.
useEditorValue()The current selected-root children.
useEditorState(selector, options?)A subscribed value derived from immutable editor state.

Hooks use the editor selected by the nearest EditorContent, EditorRoot, EditorController, or EditorProvider. useOptionalEditor() returns null without a provider or selected editor. Application IDs do not route mounted views.

import { useEditorMounted, useEditorValue } from 'platejs/react';
 
export function EditorStatus() {
  const mounted = useEditorMounted();
  const value = useEditorValue();
 
  return <p>{mounted ? `${value.length} top-level nodes` : 'Loading editor…'}</p>;
}
import { useEditorMounted, useEditorValue } from 'platejs/react';
 
export function EditorStatus() {
  const mounted = useEditorMounted();
  const value = useEditorValue();
 
  return <p>{mounted ? `${value.length} top-level nodes` : 'Loading editor…'}</p>;
}

Container and lifetime

useEditorContainerRef() returns the matching EditorContainer ref. Its current value is null before mount and after unmount. Use it to anchor editor UI to its container; it does not identify the editable DOM element.

EditorRoot and EditorContent manage editor registration and mount status. Set primary-editor eligibility through EditorRoot's primary prop and pass read-only state through their readOnly props.

Plugin state

Plugin state belongs to an installed descriptor and its editor. Let the descriptor infer the state keys and selector result.

import { definePlugin, usePluginStore } from 'platejs/react';
 
export const PanelPlugin = definePlugin('panel', {
  initialState: { open: false },
});
 
export function PanelStatus() {
  const open = usePluginStore(PanelPlugin, 'open');
 
  return <p>{open ? 'Panel open' : 'Panel closed'}</p>;
}
import { definePlugin, usePluginStore } from 'platejs/react';
 
export const PanelPlugin = definePlugin('panel', {
  initialState: { open: false },
});
 
export function PanelStatus() {
  const open = usePluginStore(PanelPlugin, 'open');
 
  return <p>{open ? 'Panel open' : 'Panel closed'}</p>;
}

Include PanelPlugin in the editor's plugins array. Use usePluginStore(PanelPlugin, (state) => state.open) for a selector callback. useEditor().plugin(PanelPlugin) returns the descriptor's inferred portal for API calls; it does not subscribe to plugin state. Outside React rendering, editor.plugin(PanelPlugin).store.get('open') reads the current value.

Focus history

useEditorFocused() reads whether the current editable has focus. useFocusedLast() reads whether the provider's editor was last focused in its owning document. It stays true while a toolbar input has focus and becomes false when another editor in that document receives focus or the focused view unmounts. Editors in separate documents keep independent focus history, and matching editor IDs do not make their instances equivalent.

import { useFocusedLast } from 'platejs/react';
 
export function EditorTools() {
  const focusedLast = useFocusedLast();
 
  return <div hidden={!focusedLast}>Editor tools</div>;
}
import { useFocusedLast } from 'platejs/react';
 
export function EditorTools() {
  const focusedLast = useFocusedLast();
 
  return <div hidden={!focusedLast}>Editor tools</div>;
}

Render this hook under EditorRoot, or under EditorController with an active editor. Use useOptionalEditor() to guard a child containing strict editor hooks while an empty controller has no editor. State, value and selection hooks require an active editor.

Explicit editors

Use <EditorProvider editor={editor}> to bind UI to an existing editor; editor={null} represents no target. This provider creates no document, history, or editable view. To retain a concrete editor type in selectors, use useEditorRuntimeState(editor, selector), useEditorViewState(editor, selector), or useEditorPluginStore(editor, Plugin, selector).

useEditorReadOnly() reads the selected view’s current permission. A captured view rejects writes after unmount. Views of one model share document content, plugin stores, and undo history.