Skip to main content


Plate plugins are objects passed to Plate plugins prop.

Creating Plugins#

Plugin Factory#

Let's create a plugin factory with createPluginFactory:

  • first param is the default plugin.
  • the only required property of the default plugin is key.
  • the naming convention is create...Plugin
  • returns a plugin factory:
    • first param override can be used to (deeply) override the default plugin.
    • second param overrideByKey can be used to (deeply) override by key a nested plugin (in plugin.plugins).
    • returns a plugin of type PlatePlugin
const createParagraphPlugin = createPluginFactory({
// -> { key: ELEMENT_PARAGRAPH }
const paragraphPlugin = createParagraphPlugin()
// -> { key: 'p', type: 'paragraph' }
const paragraphPlugin = createParagraphPlugin({ key: 'p', type: 'paragraph' })


  • To render a block element, use isElement: true.
  • To customize the rendered component, use component.
  • To enable block toggling with a hotkey, use handlers.onKeyDown: onKeyDownToggleElement
  • To define the hotkey, use options.hotkey.
    • Note that options type is set to HotkeyPlugin
const createParagraphPlugin = createPluginFactory<HotkeyPlugin>({
isElement: true,
component: ParagraphElement,
handlers: {
onKeyDown: onKeyDownToggleElement,
options: {
hotkey: ['mod+opt+0', 'mod+shift+0'],

Inline & Void#

  • To set the element as an inline element, use isInline: true.
  • To set the element as a void element, use isVoid: true.
const createTagPlugin = createPluginFactory({
isElement: true,
isInline: true,
isVoid: true,


  • To render a leaf, use isLeaf: true.
  • To customize the rendered component, use component.
  • To enable mark toggling with a hotkey, use handlers.onKeyDown: onKeyDownToggleMark
  • To define the hotkey, use options.hotkey.
  • To clear a mark when toggling, use options.clear.
const createSubscriptPlugin = createPluginFactory<ToggleMarkPlugin>({
isLeaf: true,
handlers: {
onKeyDown: onKeyDownToggleMark,
options: {
hotkey: 'mod+.',

With Overrides#

  • To override the editor methods, use withOverrides.
// Example
const createReactPlugin = {
withOverrides: withTReact

Deserialize HTML#

  • To customize HTML deserializer for this node, use deserializeHtml.
// Example
const createBoldPlugin = {
// ...
deserializeHtml: {
rules: [
{ validNodeName: ['STRONG', 'B'] },
validStyle: {
fontWeight: ['600', '700', 'bold'],

Inject Props#

  • To inject props to the component, use inject.props.
// Example
const createAlignPlugin = createPluginFactory({
// Note that we're using `then` to access to the editor.
then: (editor) => ({
inject: {
props: {
nodeKey: KEY_ALIGN,
defaultNodeValue: 'left',
styleKey: 'textAlign',
validNodeValues: ['left', 'center', 'right', 'justify'],
validTypes: [getPluginType(editor, ELEMENT_DEFAULT)],


See the following API for other use cases like:

  • editor.insertData: used by the deserializer plugins.
  • decorate: used by find & replace plugin.
  • inject.aboveComponent
  • inject.belowComponent: used by the indent list plugin.
  • inject.pluginsByKey: used by the list plugin.
  • plugins: used by the heading plugin.
  • props
  • serializeHtml



  • Property used by Plate to store the plugins by key in editor.pluginsByKey.
  • Unique and required.
  • Naming convention:
    • all Plate element keys start with ELEMENT_.
    • all Plate mark keys start with MARK_.


  • Property used by Plate to render a slate element or leaf.
  • React component with element of leaf props.



  • Properties used by the HTML deserializer core plugin for each HTML element.
  • Type is DeserializeHtml | DeserializeHtml[]
type DeserializeHtml = {
* List of HTML attribute names to store their values in `node.attributes`.
attributeNames?: string[];
* Deserialize an element.
* Use this instead of plugin.isElement if you don't want the plugin to renderElement.
* @default plugin.isElement
isElement?: boolean;
* Deserialize a leaf.
* Use this instead of plugin.isLeaf if you don't want the plugin to renderLeaf.
* @default plugin.isLeaf
isLeaf?: boolean;
* Deserialize html element to slate node.
getNode?: (element: HTMLElement) => AnyObject | undefined;
query?: (element: HTMLElement) => boolean;
* Deserialize an element:
* - if this option (string) is in the element attribute names.
* - if this option (object) values match the element attributes.
validAttribute?: string | { [key: string]: string | string[] };
* Valid element `className`.
validClassName?: string;
* Valid element `nodeName`.
* Set '*' to allow any node name.
validNodeName?: string | string[];
* Valid element style values.
* Can be a list of string (only one match is needed).
validStyle?: Partial<
Record<keyof CSSStyleDeclaration, string | string[] | undefined>
* Whether or not to include deserialized children on this node
withoutChildren?: boolean;


  • Properties used by the insertData core plugin to deserialize inserted data to a slate fragment.
  • The fragment will be inserted to the editor if not empty.
type PlatePluginInsertDataOptions = {
data: string;
dataTransfer: DataTransfer;
type PlatePluginInsertData<V extends Value = Value> = {
* Format to get data. Example data types are text/plain and text/uri-list.
format?: string;
* Query to skip this plugin.
query?: (options: PlatePluginInsertDataOptions) => boolean;
* Deserialize data to fragment
getFragment?: (
options: PlatePluginInsertDataOptions
) => EElementOrText<V>[] | undefined;
// injected
* Function called on `editor.insertData` just before `editor.insertFragment`.
* Default: if the block above the selection is empty and the first fragment node type is not inline,
* set the selected node type to the first fragment node type.
* @return if true, the next handlers will be skipped.
preInsert?: (
fragment: EElementOrText<V>[],
options: PlatePluginInsertDataOptions
) => HandlerReturnType;
* Transform the inserted data.
transformData?: (
data: string,
options: { dataTransfer: DataTransfer }
) => string;
* Transform the fragment to insert.
transformFragment?: (
fragment: EElementOrText<V>[],
options: PlatePluginInsertDataOptions
) => EElementOrText<V>[];


  • Handlers called whenever the corresponding event occurs in the editor.
  • Handlers can also be passed as Plate props. These are called after the plugins handlers.
  • Event handlers can return a boolean flag to specify whether the event can be treated as being handled.
    • If it returns true, the next handlers will not be called.
const plugin = {
handlers: {
onKeyDown: (event, editor, next) => {
// Implement custom event logic...
// When no value is returned, the next handlers will be executed when
// isPropagationStopped was not set on the event
onDrop: (event, editor, next) => {
// Implement custom event logic...
// No matter the state of the event, treat it as being handled by returning
// true here, the next handlers will be skipped
return true;
onDragStart: (event, editor, next) => {
// Implement custom event logic...
// No matter the status of the event, treat event as *not* being handled by
// returning false, the next handlers will be executed afterward
return false;

This property extends most textarea handlers like:

  • onCopy,
  • onPaste,
  • onFocus,
  • onBlur,
  • onDOMBeforeInput,
  • onKeyDown,
  • ...

The type of each handler is:

type Handler<P = PluginOptions, V extends Value, E extends PlateEditor<V> = PlateEditor<V>> = (
editor: E, plugin: WithPlatePlugin<P, V, E>
) => (event: Event) => boolean | void;


  • Property used by Plate to inject a component above other plugins component.


  • Property used by Plate to inject a component below other plugins component, i.e. above its children.


  • Property that can be used by a plugin to allow other plugins to inject code.
  • Differs from overrideByKey as this is not overriding any plugin.
  • For example, if multiple plugins have defined inject.editor.insertData.transformData for key=KEY_DESERIALIZE_HTML, insertData plugin will call all of these transformData for KEY_DESERIALIZE_HTML plugin.


  • Properties used by Plate to inject props into any node component.
* Object whose keys are node values and values are classNames which will be extended.
classNames?: AnyObject;
* Default node value.
* The node key would be unset if the node value = defaultNodeValue.
defaultNodeValue?: any;
* Node key to map to the styles.
nodeKey?: string;
* Style key to override.
* @default nodeKey
styleKey?: keyof CSSProperties;
* Transform the className.
* @default clsx(className, classNames[value])
transformClassName?: (options: TransformOptions<V>) => any;
* Transform the node value for the style or className.
* @default nodeValue
transformNodeValue?: (options: TransformOptions<V>) => any;
* Transform the style.
* @default {, [styleKey]: value }
transformStyle?: (options: TransformOptions<V>) => CSSProperties;
* List of supported node values.
validNodeValues?: any[];
* Node types required to inject the props.
* @default [ELEMENT_DEFAULT]
validTypes?: string[];
  • If you want more semantics in your content, use CSS classes instead of inline styles.
  • You can then adjust the CSS in the style sheets of your application.
  • Example:
inject: {
props: {
classNames: {
1: 'slate-indent-1',
2: 'slate-indent-2',
3: 'slate-indent-3',
.slate-indent-1 {
margin-left: 10%;
.slate-indent-2 {
margin-left: 20%;
.slate-indent-3 {
margin-left: 30%;


  • Property used by Plate to render nodes of this type as elements, i.e. renderElement.


  • Property used by inlineVoid core plugin to set elements of this type as inline.


  • Property used by Plate to render nodes of this type as leaves, i.e. renderLeaf.


  • Property used by inlineVoid core plugin to set elements of this type as void.


  • Normalize value before passing it into the editor.


  • Extended properties used by any plugin as options.
  • Its type is the second generic type of PlatePlugin.


  • Property used by Plate to deeply override plugins by key.


  • Recursive plugin support to allow having multiple plugins in a single plugin.
  • Plate eventually flattens all the plugins into the editor.


  • Property used by Plate to override node component props.
  • If function, its returning value will be shallow merged to the old props, with the old props as parameter.
  • If object, its value will be shallow merged to the old props.


  • Render a component above Editable.


  • Render a component above Slate.


  • Render a component after Editable.


  • Render a component before Editable.


  • Property used by serializeHtml util to replace renderElement and renderLeaf when serializing a node of this type.


  • Recursive plugin merging.
  • Can be used to derive plugin fields from editor and plugin.
  • The returned value will be deeply merged to the plugin.
  • Type is:
editor: E,
plugin: WithPlatePlugin<P, V, E>
) => Partial<PlatePlugin<P, V, E>> | void;


  • Property used by Plate to render a node by type.
  • It requires slate element properties to have a type property with the plugin type as value.
    • Example: { type: 'p' } where plugin type is 'p'.
  • It requires slate leaf properties to have the plugin type value as key and true as value.
    • Example: { bold: true } where plugin type is 'bold'.
  • Default is plugin key.


  • Use any React hooks here. Each plugin useHooks will be called in a React component.