Skip to Content
GuidesCreating Custom Plugins

Creating Custom Plugins

You can create your own plugins and register them alongside the built-in ones.

Minimal plugin

my-app/plugins/strikethrough.ts
import { createPlugin } from '@inkstream/editor-core' import { toggleMark } from 'prosemirror-commands' export const strikethroughPlugin = createPlugin({ name: 'strikethrough', marks: { strikethrough: { parseDOM: [{ tag: 's' }, { tag: 'del' }, { style: 'text-decoration=line-through' }], toDOM: () => ['s', 0], }, }, getToolbarItems: (schema) => [ { id: 'strikethrough', icon: 'S̶', tooltip: 'Strikethrough', command: toggleMark(schema.marks.strikethrough), isActive: (state) => state.selection.$from.marks().some(m => m.type === schema.marks.strikethrough), }, ], getKeymap: (schema) => ({ 'Mod-Shift-x': toggleMark(schema.marks.strikethrough), }), })

Plugin with a custom node

my-app/plugins/callout.ts
import { createPlugin } from '@inkstream/editor-core' import type { Command } from 'prosemirror-state' const insertCallout: Command = (state, dispatch) => { const { callout } = state.schema.nodes if (!callout) return false if (dispatch) { const node = callout.createAndFill()! dispatch(state.tr.replaceSelectionWith(node)) } return true } export const calloutPlugin = createPlugin({ name: 'callout', nodes: { callout: { group: 'block', content: 'inline*', parseDOM: [{ tag: 'div[data-type="callout"]' }], toDOM: () => ['div', { 'data-type': 'callout', class: 'callout' }, 0], }, }, getToolbarItems: (schema) => [ { id: 'callout', icon: '💡', tooltip: 'Insert callout', command: insertCallout, }, ], })

Using your plugin

import { RichTextEditor } from '@inkstream/react-editor' import { boldPlugin } from '@inkstream/bold' import { calloutPlugin } from './plugins/callout' <RichTextEditor plugins={[boldPlugin, calloutPlugin]} toolbarLayout={['bold', '|', 'callout']} />

Plugins are registered in the order they appear in the plugins array. Node/mark names must be globally unique across all registered plugins.