Plate plugins are descriptors passed to the Plate plugins prop. Installed plugin APIs are inferred on editor.api under the plugin name. Pass the descriptor to editor.plugin(MyPlugin) when generic code needs the exact plugin API, update commands, identity, or editor-local state; React components subscribe with usePluginStore.
Plugin constructor, extension, configuration, event, codec, and injection callbacks receive the current plugin context when their callback contract supports it:
export type UploadPluginState = {
active: boolean;
};
const uploadInitialState
export type UploadPluginState = {
active: boolean;
};
const uploadInitialState: UploadPluginState = {
active: false,
};
export const UploadPlugin = definePlatePlugin("upload", {
schema: {
element: {
content: schema.content.text({ default: 'text', min: 1 }),
},
},
initialState: uploadInitialState,
api: ({ store }) => ({
start: () => store.set({ active: true }),
}),
read: ({ state }) => ({
isReady: () => !!state.selection(),
}),
update: ({ tx, type }) => ({
insert: () => tx.nodes.insert({ children: [{ text: "" }], type }),
}),
}).extend(({ api, read, store, update }) => ({
on: {
focus: () => {
if (!read.isReady()) return;
store.set({ active: true });
api.start();
update.insert();
},
},
}));Use store, api, read, update, name, plugin, and installed
directly for the current plugin. Use editor for editor-wide operations,
another plugin, or transaction metadata unavailable on the scoped update
facade. Specialized callbacks such as shortcut handlers and input rules may
only receive editor; use an exact typed plugin portal there.
Unique identifier Plate uses to resolve the descriptor through editor.plugin(MyPlugin).
Plugin descriptors or dynamic names targeted by the plugin's schema contributions and injected behavior.
[]Plugin-owned API functions exposed through editor.api[MyPlugin.name] and the
exact editor.plugin(MyPlugin).api portal. Both paths reference the same
immutable API object. Declare api as a factory even when it needs no
context. The factory receives one object containing the normal Plate plugin
context; it never receives positional editor, context arguments. Authors
declare independent methods in the constructor and use .extend({api}) only
when they need an earlier-stage type or are adapting an imported/prebuilt
descriptor. Genuinely editor-wide capabilities use the same root api field;
Plite projects it under the plugin name.
State-bound reads owned by the plugin. Plate publishes them under
editor.read[name] and through editor.plugin(MyPlugin).read. Declare
read as a factory, even when the returned methods need no authoring context.
Plate constructs the namespace once per plugin configuration. Return methods
or nested method records; compute document values when a method runs. Stable
constants and host services belong in api.
Pure state-first derivations over the plugin's editor-local store. React
consumers subscribe to them through usePluginStore.
Transaction commands provided by the plugin. Call one through
editor.plugin(MyPlugin).update.method() or compose it inside
editor.update((tx) => tx.plugin(MyPlugin).method()). update is factory-only:
return the command object from the callback instead of declaring a static
object.
The seed for this plugin's mutable editor-local store. Package authors declare
an exported *PluginState beside an exported plugin and check its defaults
through a typed constant or explicit factory return type. Use the callback form
when the seed depends on the resolved plugin context. App consumers override
the seed with one final .configure({ initialState: { ... } }). Runtime code
reads and updates the installed store through editor.plugin(MyPlugin).store.
The ordinary component for this plugin's node. Declare it in
defineBasePlugin(name, { component }) or
definePlatePlugin(name, { component }) for
static/RSC and live rendering. Replace it with one terminal
.configure({component}). Base .extend() does not accept it. Use
toPlatePlugin() at the owning React adapter to publish a reusable
Plate-layer descriptor or add Plate-only authoring; a terminal consumer does
not convert merely to set component.
Schema-aware product and foreign format mappings. Use the contextual
defineCodecs(map) helper for self/product codecs or
defineCodecs(TargetPlugin, map) for foreign contributions.
Lifecycle and DOM event handlers. Child names do not repeat the on prefix:
use nodeChange, textChange, keyDown, paste, and their capture variants.
Defines how the plugin injects functionality into other plugins or the editor.
Declares the plugin's Plite model through its element, mark, keyed
properties, and contentRoots fields. A schema factory receives the plugin
name, its configured initialState, targetElementTypes, and Plate
relationship helpers. name identifies the capability only. Installed AST
identity is published through schema.type for an element plugin and
schema.key for a primary-mark plugin. Author callbacks may also use
schema.properties.<localId> for additional declared properties; consumer
portals do not expose that map. Behavior and aggregate-property portals omit
schema.
Boolean text properties use
property.boolean({ default: false, omitDefault: true }).
Inside update, tx.nodes.set(props, options) accepts a typed property patch,
while unset(key, options) removes exact properties. Aliases use the exact
authored property handle's key in a computed patch. Prefix families and
cross-node behavior use semantic update methods.
Defines editing behavior for the plugin's compiled schema identity.
Provides component replacement and weak cross-package plugin adaptation.
Defines whole-input HTML parsing behavior.
Defines how the plugin renders components.
Defines keyboard shortcuts for the plugin.
Input rules owned by this plugin. Use the typed rule factories and keep the rules beside the feature that owns the resulting behavior.
Plate plugin or raw Plite extension descriptors that must be installed before this plugin. Pass the descriptor objects themselves so Plate preserves dependency identity and type inference.
Plate plugin or raw Plite extension descriptors that cannot be installed
with this plugin. Import both reference types from platejs; Plite-only
libraries can import EditorExtensionReference from @platejs/plite.
Typed middleware over declared Plite editorReads descriptors.
Pure typed command interceptors declared with handle or around.
Deterministic changed-range structural repairs.
Typed persisted or runtime state descriptors.
Typed commit-effect descriptors and codecs.
Derived state providers.
Ordered values bound to typed extension points. Host clipboard insertion is
a direct clipboardHandler(...) contribution, never a root clipboard
field. clipboardHandler({ insertData }) is the sole form. The owning
extension or Plate stage contextually infers transaction from its installed
update capabilities. next delegates to the next handler.
Owns synchronous resources. Defer work that must observe publication with
context.afterPublish(...).
Validates the detached candidate before activation.
Enables or disables the plugin. Used by Plate to determine if the plugin should be used.
Property used by Plate to decorate editor ranges.
Prepares complete document input after application migrations and before
schema fitting. It runs during initialization and complete
editor.update.value.replace(...) loads. Use it for installed current-schema
invariants, not source-version migrations.
Hook called when the editor is initialized.
Configures which plugin functionalities should only be active when the editor is not read-only.
Can be either a boolean or an object configuration:
type EditOnlyConfig = {
render?: boolean; // default: true
on?: boolean; // default: true
inject?: boolean; // default: true
prepareDocument?: boolean; // default: false
};type EditOnlyConfig = {
render?: boolean; // default: true
Applies one terminal consumer configuration and returns a descriptor that
cannot be configured or extended again. Use the object form for definition
fields. The callback form can derive existing initialState, on, render,
or shortcuts from the resolved editor context. Contextual extensions
declared before this call read the configured values, while the configuration
remains the final override.
HeadingPlugin.configure({
rules: { break: { empty: 'reset' } },
});HeadingPlugin.configure({
rules: { break: { empty: 'reset' } },
});Adds a contribution to an imported/prebuilt descriptor, a shared factory the
constructor cannot access, or types introduced by an earlier contribution. Put independent
fields directly in defineBasePlugin() or definePlatePlugin(). Complete
every .extend() call before applying consumer .configure(). The returned
PlatePlugin carries the contribution's inferred capabilities.
The contribution fields have distinct owners:
api: plugin-scoped immutable servicesread: snapshot or transaction-local readsselectors: pure projections of editor-local plugin stateupdate: plugin-scoped transaction-bound mutationsreadMiddleware, commands, corrections, stateFields, effectTypes,
facetProviders, contributions, on, activate, and
: native Plite capabilities declared directly on the pluginThe current editor instance.
The current plugin instance.
Creates a schema-checked codec declaration inside the constructor's
codecs callback, or inside .extend() when the codec needs an earlier
capability. Pass one MIME-keyed map for self/product codecs, or pass a
target plugin plus the map for a foreign contribution.
Reads, updates, and subscribes to the current plugin's editor-local state. Named selectors are pure functions of that state.
For more detailed information on specific aspects of Plate plugins, refer to the individual guides on Plugin Configuration, Plugin Methods, Plugin Context, Plugin Components, and Plugin Shortcuts.
Use DefinitionOf<typeof Plugin> as the sole public way to extract a
descriptor's inferred definition.
Usage example:
export type MyPluginState = {
customOption: boolean;
};
export const MyPlugin = definePlatePlugin("myPlugin", {
initialState: {
customOption: false,
} satisfies MyPluginState,
api: ({ store }) => ({
getData: () => String(store.get("customOption")),
}),
update: ({ tx }) => ({
run: () => tx.selection.collapse(),
}),
});
type MyDefinition = DefinitionOf<typeof MyPlugin>;export type MyPluginState = {
customOption: boolean;
};
export const MyPlugin = definePlatePlugin("myPlugin", {
initialState: {
customOption: false,
} satisfies MyPluginState,
api: ({ store }) => ({
getData: () => String(store.get("customOption")),
}),
update: ({ tx }) => ({
run: () => tx.selection.collapse(),
}),
});
When set to true (boolean):
render, on, and inject.nodeProps are only active when editor is not read-onlyprepareDocument remains active regardless of read-only stateWhen set to an object:
true) except prepareDocument which defaults to always active (false)false to make it always active regardless of read-only stateprepareDocument, set to true to make it edit-onlyExamples:
// All features (except prepareDocument) are edit-only
editOnly: true;
// prepareDocument is edit-only, others remain edit-only by default
editOnly: {
prepareDocument: true;
}
// render is always active, others follow default behavior
editOnly: {
render: false;
}// All features (except prepareDocument) are edit-only
editOnly: true;
// prepareDocument is edit-only, others remain edit-only by default
editOnly: {
prepareDocument: true;
}
// render is always active, others follow default behavior
editOnly: {
render: false;
}validatecodecs: the declaration returned by context-bound defineCodecsIndependently reusable standalone Plite descriptors use
defineExtension from @platejs/plite. Plate plugins declare the same
native capabilities at their root.
Use defineCodecs(map) for self/product codecs and
defineCodecs(TargetPlugin, map) for foreign codecs. The helper injects the
foreign target. The map remains MIME-keyed; its 'text/html' value accepts one
schema-aware rule or a non-empty ordered rule tuple. defineCodecs is the one
inline inference anchor—do not author direct codec maps or manual target
fields.
defineBasePlugin() / definePlatePlugin() own every independent declaration
field, including api, read, selectors, update, native Plite fields, and
codecs.