Plugin Methods
Explore the various methods available for extending Plate plugins.
Configuration Methods
When extending plugins, all properties are deeply merged by default, with two exceptions: arrays are replaced entirely, and the options object is shallow merged.
.configure
The .configure method allows you to override the plugin's configuration.
const ConfiguredPlugin = MyPlugin.configure({
  options: {
    myOption: 'new value',
  },
});Access current configuration:
const ConfiguredPlugin = MyPlugin.configure(({ getOptions }) => ({
  options: {
    ...getOptions(),
    myOption: `${getOptions().myOption} + extra`,
  },
}));- Modifies existing properties
 - Doesn't add new properties
 - Last configuration applied is used
 - Maintains original plugin type
 
.configurePlugin
The .configurePlugin method allows you to configure the properties of a nested plugin:
const TablePlugin = createPlatePlugin({
  key: 'table',
  plugins: [TableCellPlugin],
}).configurePlugin(TableCellPlugin, {
  options: {
    cellOption: 'modified',
  },
});- Configures nested plugins within parent plugin
 - Modifies existing properties only
 - Useful for adjusting sub-plugin behavior
 
.extend
The .extend method allows you to extend the plugin's configuration and functionality.
const ExtendedPlugin = MyPlugin.extend({
  options: {
    newOption: 'new value',
  },
});Access current configuration and editor:
const ExtendedPlugin = MyPlugin.extend(({ editor, plugin }) => ({
  options: {
    newOption: 'new value',
  },
  handlers: {
    onKeyDown: () => {
      // Custom key down logic
    },
  },
}));- Adds new properties or modifies existing ones
 - Returns new plugin instance with extended types
 - Chainable for sequential extensions
 
.extendPlugin
The .extendPlugin method allows you to extend the configuration and functionality of a nested plugin:
const TablePlugin = createPlatePlugin({
  key: 'table',
  plugins: [TableCellPlugin],
}).extendPlugin(TableCellPlugin, {
  options: {
    newCellOption: 'added',
  },
  handlers: {
    onKeyDown: () => {
      // Custom key down logic for table cells
    },
  },
});- Extends nested plugins within parent plugin
 - Can add new properties and modify existing ones
 - Returns new parent plugin instance
 
.extendOptions
Difference between .configure and .extend
While both methods can be used to modify plugin configuration, they have some key differences:
- Chaining: 
.extendis chainable, while.configureis not. - Type extension: 
.extendreturns a new plugin instance with extended types, while.configuremaintains the original type. - New properties: 
.extendcan add new properties to the plugin configuration, while.configureonly modifies existing ones. 
Choose the appropriate method based on whether you need to extend the plugin's type and functionality (use .extend) or simply modify existing configuration (use .configure).
const CounterPlugin = createPlatePlugin({
  key: 'counter',
  options: {
    count: 0,
  },
}).extendOptions(({ getOptions }) => ({
  doubleCount: () => getOptions().count * 2,
  isEven: () => getOptions().count % 2 === 0,
}));Usage in components:
const CounterComponent = () => {
  const { useOption } = useEditorPlugin(CounterPlugin);
  
  const count = useOption('count');
  const doubleCount = useOption('doubleCount');
  const isEven = useOption('isEven');
 
  return (
    <div>
      <p>Count: {count}</p>
      <p>Double Count: {doubleCount}</p>
      <p>Is Even: {isEven ? 'Yes' : 'No'}</p>
    </div>
  );
};- Creates derived state from plugin options
 - Accessible via 
getOptionanduseOption - Recomputed when underlying options change
 
.withComponent
The withComponent method allows you to set or replace the component associated with a plugin.
const ParagraphPlugin = createPlatePlugin({
  key: 'p',
  node: {
    isElement: true,
    type: 'p',
  },
}).withComponent(ParagraphElement);API and Transforms
Plugins can define their own API methods and transforms that will be merged into the editor's API and transforms.
This is done using the extendApi, extendEditorApi, extendTransforms, and extendEditorTransforms methods.
.extendApi
Use extendApi to add plugin-specific API methods:
const MyPlugin = createPlatePlugin({
  key: 'myPlugin',
}).extendApi(() => ({
  pluginMethod: () => 'plugin method result',
}));
 
// Access: editor.api.myPlugin.api.pluginMethod();.extendEditorApi
Use extendEditorApi to add root-level API methods:
const MyPlugin = createPlatePlugin({
  key: 'myPlugin',
}).extendEditorApi(({ getOptions }) => ({
  editorMethod: () => getOptions().someOption,
}));
 
// Access: editor.api.editorMethod();.extendTransforms
Use extendTransforms to add plugin-specific transform methods:
const MyPlugin = createPlatePlugin({
  key: 'myPlugin',
}).extendTransforms(() => ({
  pluginTransform: () => {
    // Custom transform logic
  },
}));
 
// Access: editor.tf.myPlugin.pluginTransform();
// Or: editor.transforms.myPlugin.pluginTransform();.extendEditorTransforms
Use extendEditorTransforms to add root-level transform methods:
const MyPlugin = createPlatePlugin({
  key: 'myPlugin',
}).extendEditorTransforms(({ editor }) => ({
  editorTransform: () => {
    // Custom editor transform logic
  },
}));
 
// Access: editor.tf.editorTransform();.overrideEditor
The overrideEditor method is used specifically for overriding existing editor methods without altering the plugin's type:
const MyPlugin = createPlatePlugin({
  key: 'myPlugin',
}).overrideEditor(({ editor, tf: { insertText }, api: { isInline } }) => ({
  transforms: {
    insertText(text, options) {
      // Override insertText behavior
      insertText(text, options);
    },
  },
  api: {
    isInline(element) {
      // Override isInline behavior
      return isInline(element);
    },
  },
}));- Overrides existing editor methods only
 - Cannot add new methods
 - Provides access to original methods
 
- Used specifically for overriding existing editor methods
 - Returns the overridden methods wrapped in 
transformsorapiobjects - Cannot add new methods (use 
extendEditorTransformsorextendEditorApiinstead) - Provides access to original methods through the context
 
Difference between API and Transforms
While there is currently no core difference between API and Transforms in Plate, they serve distinct purposes and are designed with future extensibility in mind:
- 
Transforms:
- Store all Slate transforms and editor operations here. Structured to potentially support middlewares in the future, allowing for more complex transform pipelines and devtools.
 - Typically used for operations that modify the editor state, such as inserting, deleting, or transforming content.
 - Example: 
editor.tf.toggle.block(),editor.tf.toggle.mark({ key: 'bold' }) 
 - 
API:
- Store all queries, utility functions, and other methods that don't directly modify the editor state.
 - Example: 
editor.api.save(),editor.api.debug.log() 
 
Chaining Extensions
You can chain these methods to create a comprehensive plugin:
const MyPlugin = createPlatePlugin({
  key: 'myPlugin',
  options: {
    baseValue: 5,
  },
})
  .extendApi(() => ({
    pluginMethod: () => 'plugin method',
  }))
  .extendEditorApi(({ getOptions }) => ({
    multiply: (factor: number) => getOptions().baseValue * factor,
  }))
  .extendTransforms(() => ({
    pluginTransform: () => {
      // Plugin-specific transform
    },
  }))
  .extendEditorTransforms(({ editor }) => ({
    editorTransform: () => {
      // Editor-specific transform
    },
  }));
editor.api.myPlugin.api.pluginMethod();
editor.api.multiply(3);
editor.tf.myPlugin.pluginTransform();
editor.tf.editorTransform();Convert Slate Plugin to Plate Plugin
toPlatePlugin
Convert typed Slate plugin to Plate plugin:
const CodeBlockPlugin = toPlatePlugin(createSlatePlugin({ key: 'code_block' }), {
  handlers: {},
  options: { hotkey: ['mod+opt+8', 'mod+shift+8'] },
});