Skip to main content

Plugins

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,
})
// -> { key: ELEMENT_PARAGRAPH }
const paragraphPlugin = createParagraphPlugin()
// -> { key: 'p', type: 'paragraph' }
const paragraphPlugin = createParagraphPlugin({ key: 'p', type: 'paragraph' })

Element#

  • 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>({
key: ELEMENT_PARAGRAPH,
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({
key: ELEMENT_TAG,
isElement: true,
isInline: true,
isVoid: true,
})

Leaf#

  • 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>({
key: MARK_SUBSCRIPT,
isLeaf: true,
handlers: {
onKeyDown: onKeyDownToggleMark,
},
options: {
hotkey: 'mod+.',
clear: MARK_SUBSCRIPT,
},
});

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({
key: KEY_ALIGN,
// 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)],
},
},
}),
});

Others#

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

PlatePlugin#

key#

  • 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_.

component#

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

decorate#

deserializeHtml#

  • 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;
}

editor.insertData#

  • 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#

  • 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;

inject.aboveComponent#

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

inject.belowComponent#

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

inject.pluginsByKey#

  • 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.

inject.props#

  • 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 { ...style, [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:
createIndentPlugin({
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%;
}

isElement#

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

isInline#

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

isLeaf#

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

isVoid#

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

normalizeInitialValue#

  • Normalize value before passing it into the editor.

options#

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

overrideByKey#

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

plugins#

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

props#

  • 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.

renderAboveEditable#

  • Render a component above Editable.

renderAboveSlate#

  • Render a component above Slate.

renderAfterEditable#

  • Render a component after Editable.

renderBeforeEditable#

  • Render a component before Editable.

serializeHtml#

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

then#

  • 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;

type#

  • 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.

useHooks#

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

withOverrides#