Skip to content

Extensions

Every feature in ProseKit ships as an extension. Extensions are small, plain values you compose with union(...) and pass to createEditor.

import { createEditorfunction createEditor<E extends Extension>(options: EditorOptions<E>): Editor<E>
@public
, unionfunction union<const E extends readonly Extension[]>(...exts: E): Union<E> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as arguments or a single array containing multiple extensions.
@throwsIf no extensions are provided.@example```ts function defineFancyNodes() { return union( defineFancyParagraph(), defineFancyHeading(), ) } ```@example```ts function defineFancyNodes() { return union([ defineFancyParagraph(), defineFancyHeading(), ]) } ```@public
} from 'prosekit/core'
import { defineDocfunction defineDoc(): DocExtension
@public
} from 'prosekit/extensions/doc'
import { defineParagraphfunction defineParagraph(): ParagraphExtension
@publicDefines a paragraph node. The paragraph node spec has the highest priority, because it should be the default block node for most cases.
} from 'prosekit/extensions/paragraph'
import { defineTextfunction defineText(): TextExtension
@public
} from 'prosekit/extensions/text'
const extensionconst extension: Union<readonly [DocExtension, TextExtension, ParagraphExtension]> = unionunion<readonly [DocExtension, TextExtension, ParagraphExtension]>(exts_0: DocExtension, exts_1: TextExtension, exts_2: ParagraphExtension): Union<readonly [DocExtension, TextExtension, ParagraphExtension]> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as arguments or a single array containing multiple extensions.
@throwsIf no extensions are provided.@example```ts function defineFancyNodes() { return union( defineFancyParagraph(), defineFancyHeading(), ) } ```@example```ts function defineFancyNodes() { return union([ defineFancyParagraph(), defineFancyHeading(), ]) } ```@public
(
defineDocfunction defineDoc(): DocExtension
@public
(),
defineTextfunction defineText(): TextExtension
@public
(),
defineParagraphfunction defineParagraph(): ParagraphExtension
@publicDefines a paragraph node. The paragraph node spec has the highest priority, because it should be the default block node for most cases.
(),
) const editorconst editor: Editor<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>> = createEditorcreateEditor<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>>(options: EditorOptions<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>>): Editor<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>>
@public
({ extensionEditorOptions<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>>.extension: Union<readonly [DocExtension, TextExtension, ParagraphExtension]>
The extension to use when creating the editor.
})

Each feature in prosekit/extensions/<name> exposes a single high-level factory that bundles every related piece (schema, commands, keymap, input rules) into one extension. Examples: defineBold(), defineHeading(), defineCodeBlock(). Use these as your building blocks; if you need to customize a feature beyond what its options expose, drop down to a custom extension instead. See Custom Extensions.

defineBasicExtension is a ready-made bundle that's identical to:

import { defineBaseCommandsfunction defineBaseCommands(): BaseCommandsExtension
Add some base commands
@public
, defineBaseKeymapfunction defineBaseKeymap({ priority, preferBlockSelection, }?: BaseKeymapOptions): BaseKeymapExtension
Defines some basic key bindings.
@paramoptions@public
, defineHistoryfunction defineHistory({ depth, newGroupDelay, }?: HistoryOptions): HistoryExtension
Add undo/redo history to the editor.
@paramoptions@public
, unionfunction union<const E extends readonly Extension[]>(...exts: E): Union<E> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as arguments or a single array containing multiple extensions.
@throwsIf no extensions are provided.@example```ts function defineFancyNodes() { return union( defineFancyParagraph(), defineFancyHeading(), ) } ```@example```ts function defineFancyNodes() { return union([ defineFancyParagraph(), defineFancyHeading(), ]) } ```@public
} from 'prosekit/core'
import { defineBlockquotefunction defineBlockquote(): BlockquoteExtension
@public
} from 'prosekit/extensions/blockquote'
import { defineBoldfunction defineBold(): BoldExtension
@public
} from 'prosekit/extensions/bold'
import { defineCodefunction defineCode(): CodeExtension
@public
} from 'prosekit/extensions/code'
import { defineCodeBlockfunction defineCodeBlock(): CodeBlockExtension
Adds `codeBlock` nodes to the editor. This includes the following extensions: - {@link defineCodeBlockSpec } - {@link defineCodeBlockInputRule } - {@link defineCodeBlockEnterRule } - {@link defineCodeBlockKeymap } - {@link defineCodeBlockCommands } .
@public
} from 'prosekit/extensions/code-block'
import { defineDocfunction defineDoc(): DocExtension
@public
} from 'prosekit/extensions/doc'
import { defineGapCursorfunction defineGapCursor(): GapCursorExtension
Capture clicks near and arrow-key-motion past places that don't have a normally selectable position nearby, and create a gap cursor selection for them. The cursor is drawn as an element with class `ProseMirror-gapcursor`. You can either include `prosekit/extensions/gap-cursor.css` or add your own styles to make it visible. See [prosemirror-gapcursor](https://github.com/ProseMirror/prosemirror-gapcursor) for more information.
@public
} from 'prosekit/extensions/gap-cursor'
import { defineHardBreakfunction defineHardBreak(): HardBreakExtension
@public
} from 'prosekit/extensions/hard-break'
import { defineHeadingfunction defineHeading(): HeadingExtension
@public
} from 'prosekit/extensions/heading'
import { defineHorizontalRulefunction defineHorizontalRule(): HorizontalRuleExtension
@public
} from 'prosekit/extensions/horizontal-rule'
import { defineImagefunction defineImage(): ImageExtension
@public
} from 'prosekit/extensions/image'
import { defineItalicfunction defineItalic(): ItalicExtension
@public
} from 'prosekit/extensions/italic'
import { defineLinkfunction defineLink(): LinkExtension
@public
} from 'prosekit/extensions/link'
import { defineListfunction defineList(): ListExtension
@public
} from 'prosekit/extensions/list'
import { defineModClickPreventionfunction defineModClickPrevention(): ModClickPreventionExtension
By default, clicking a node while holding the mod key will select the node. This extension disables that behavior.
@public
} from 'prosekit/extensions/mod-click-prevention'
import { defineParagraphfunction defineParagraph(): ParagraphExtension
@publicDefines a paragraph node. The paragraph node spec has the highest priority, because it should be the default block node for most cases.
} from 'prosekit/extensions/paragraph'
import { defineStrikefunction defineStrike(): StrikeExtension
@public
} from 'prosekit/extensions/strike'
import { defineTablefunction defineTable(): TableExtension
@public
} from 'prosekit/extensions/table'
import { defineTextfunction defineText(): TextExtension
@public
} from 'prosekit/extensions/text'
import { defineUnderlinefunction defineUnderline(): UnderlineExtension
@public
} from 'prosekit/extensions/underline'
import { defineVirtualSelectionfunction defineVirtualSelection(): VirtualSelectionExtension
Shows a virtual selection when the editor is not focused. When the editor is not focused, the selected inline content will be wrapped in a `<span>` element with the class `prosekit-virtual-selection`. This is useful when you want to move the focus to an element outside the editor, but still want to show the selection.
@public
} from 'prosekit/extensions/virtual-selection'
function defineBasicExtensionfunction defineBasicExtension(): Union<readonly [DocExtension, TextExtension, ParagraphExtension, HeadingExtension, ListExtension, BlockquoteExtension, ImageExtension, HorizontalRuleExtension, HardBreakExtension, TableExtension, CodeBlockExtension, ItalicExtension, BoldExtension, UnderlineExtension, ... 8 more ..., PlainExtension]>() { return unionunion<readonly [DocExtension, TextExtension, ParagraphExtension, HeadingExtension, ListExtension, BlockquoteExtension, ImageExtension, HorizontalRuleExtension, HardBreakExtension, TableExtension, CodeBlockExtension, ItalicExtension, BoldExtension, UnderlineExtension, ... 8 more ..., PlainExtension]>(exts_0: DocExtension, exts_1: TextExtension, exts_2: ParagraphExtension, exts_3: HeadingExtension, exts_4: ListExtension, exts_5: BlockquoteExtension, exts_6: ImageExtension, exts_7: HorizontalRuleExtension, exts_8: HardBreakExtension, exts_9: TableExtension, exts_10: CodeBlockExtension, exts_11: ItalicExtension, exts_12: BoldExtension, exts_13: UnderlineExtension, exts_14: StrikeExtension, exts_15: CodeExtension, exts_16: LinkExtension, exts_17: PlainExtension, exts_18: BaseCommandsExtension, exts_19: HistoryExtension, exts_20: PlainExtension, exts_21: PlainExtension, exts_22: PlainExtension): Union<...> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as arguments or a single array containing multiple extensions.
@throwsIf no extensions are provided.@example```ts function defineFancyNodes() { return union( defineFancyParagraph(), defineFancyHeading(), ) } ```@example```ts function defineFancyNodes() { return union([ defineFancyParagraph(), defineFancyHeading(), ]) } ```@public
(
// Nodes defineDocfunction defineDoc(): DocExtension
@public
(),
defineTextfunction defineText(): TextExtension
@public
(),
defineParagraphfunction defineParagraph(): ParagraphExtension
@publicDefines a paragraph node. The paragraph node spec has the highest priority, because it should be the default block node for most cases.
(),
defineHeadingfunction defineHeading(): HeadingExtension
@public
(),
defineListfunction defineList(): ListExtension
@public
(),
defineBlockquotefunction defineBlockquote(): BlockquoteExtension
@public
(),
defineImagefunction defineImage(): ImageExtension
@public
(),
defineHorizontalRulefunction defineHorizontalRule(): HorizontalRuleExtension
@public
(),
defineHardBreakfunction defineHardBreak(): HardBreakExtension
@public
(),
defineTablefunction defineTable(): TableExtension
@public
(),
defineCodeBlockfunction defineCodeBlock(): CodeBlockExtension
Adds `codeBlock` nodes to the editor. This includes the following extensions: - {@link defineCodeBlockSpec } - {@link defineCodeBlockInputRule } - {@link defineCodeBlockEnterRule } - {@link defineCodeBlockKeymap } - {@link defineCodeBlockCommands } .
@public
(),
// Marks defineItalicfunction defineItalic(): ItalicExtension
@public
(),
defineBoldfunction defineBold(): BoldExtension
@public
(),
defineUnderlinefunction defineUnderline(): UnderlineExtension
@public
(),
defineStrikefunction defineStrike(): StrikeExtension
@public
(),
defineCodefunction defineCode(): CodeExtension
@public
(),
defineLinkfunction defineLink(): LinkExtension
@public
(),
// Others defineBaseKeymapfunction defineBaseKeymap({ priority, preferBlockSelection, }?: BaseKeymapOptions): BaseKeymapExtension
Defines some basic key bindings.
@paramoptions@public
(),
defineBaseCommandsfunction defineBaseCommands(): BaseCommandsExtension
Add some base commands
@public
(),
defineHistoryfunction defineHistory({ depth, newGroupDelay, }?: HistoryOptions): HistoryExtension
Add undo/redo history to the editor.
@paramoptions@public
(),
defineGapCursorfunction defineGapCursor(): GapCursorExtension
Capture clicks near and arrow-key-motion past places that don't have a normally selectable position nearby, and create a gap cursor selection for them. The cursor is drawn as an element with class `ProseMirror-gapcursor`. You can either include `prosekit/extensions/gap-cursor.css` or add your own styles to make it visible. See [prosemirror-gapcursor](https://github.com/ProseMirror/prosemirror-gapcursor) for more information.
@public
(),
defineVirtualSelectionfunction defineVirtualSelection(): VirtualSelectionExtension
Shows a virtual selection when the editor is not focused. When the editor is not focused, the selected inline content will be wrapped in a `<span>` element with the class `prosekit-virtual-selection`. This is useful when you want to move the focus to an element outside the editor, but still want to show the selection.
@public
(),
defineModClickPreventionfunction defineModClickPrevention(): ModClickPreventionExtension
By default, clicking a node while holding the mod key will select the node. This extension disables that behavior.
@public
(),
) }

Copy and tweak that body if you need a smaller set than defineBasicExtension provides.

You can union a bundle with extra extensions to add features:

import { defineBasicExtensionfunction defineBasicExtension(): BasicExtension
Define a basic extension that includes some common functionality. You can copy this function and customize it to your needs. It's a combination of the following extension functions: - {@link defineDoc } - {@link defineText } - {@link defineParagraph } - {@link defineHeading } - {@link defineList } - {@link defineBlockquote } - {@link defineImage } - {@link defineHorizontalRule } - {@link defineHardBreak } - {@link defineTable } - {@link defineCodeBlock } - {@link defineItalic } - {@link defineBold } - {@link defineUnderline } - {@link defineStrike } - {@link defineCode } - {@link defineLink } - {@link defineBaseKeymap } - {@link defineBaseCommands } - {@link defineHistory } - {@link defineGapCursor } - {@link defineVirtualSelection } - {@link defineModClickPrevention }
@public
} from 'prosekit/basic'
import { createEditorfunction createEditor<E extends Extension>(options: EditorOptions<E>): Editor<E>
@public
, unionfunction union<const E extends readonly Extension[]>(...exts: E): Union<E> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as arguments or a single array containing multiple extensions.
@throwsIf no extensions are provided.@example```ts function defineFancyNodes() { return union( defineFancyParagraph(), defineFancyHeading(), ) } ```@example```ts function defineFancyNodes() { return union([ defineFancyParagraph(), defineFancyHeading(), ]) } ```@public
} from 'prosekit/core'
import { defineCodeBlockShikifunction defineCodeBlockShiki({ nodeTypes, themes, langs, ...rest }?: CodeBlockShikiOptions): Extension
Adds syntax highlighting to code blocks using the [Shiki](https://github.com/shikijs/shiki) package. It will set two CSS variables on the code block elements: - `--prosemirror-highlight`: sets text color - `--prosemirror-highlight-bg`: sets background color
@paramoptions - The options to configure the Shiki highlighter.@public
} from 'prosekit/extensions/code-block'
const extensionconst extension: Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]> = unionunion<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>(exts_0: BasicExtension, exts_1: Extension<ExtensionTyping<any, any, any>>): Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as arguments or a single array containing multiple extensions.
@throwsIf no extensions are provided.@example```ts function defineFancyNodes() { return union( defineFancyParagraph(), defineFancyHeading(), ) } ```@example```ts function defineFancyNodes() { return union([ defineFancyParagraph(), defineFancyHeading(), ]) } ```@public
(
defineBasicExtensionfunction defineBasicExtension(): BasicExtension
Define a basic extension that includes some common functionality. You can copy this function and customize it to your needs. It's a combination of the following extension functions: - {@link defineDoc } - {@link defineText } - {@link defineParagraph } - {@link defineHeading } - {@link defineList } - {@link defineBlockquote } - {@link defineImage } - {@link defineHorizontalRule } - {@link defineHardBreak } - {@link defineTable } - {@link defineCodeBlock } - {@link defineItalic } - {@link defineBold } - {@link defineUnderline } - {@link defineStrike } - {@link defineCode } - {@link defineLink } - {@link defineBaseKeymap } - {@link defineBaseCommands } - {@link defineHistory } - {@link defineGapCursor } - {@link defineVirtualSelection } - {@link defineModClickPrevention }
@public
(),
defineCodeBlockShikifunction defineCodeBlockShiki({ nodeTypes, themes, langs, ...rest }?: CodeBlockShikiOptions): Extension
Adds syntax highlighting to code blocks using the [Shiki](https://github.com/shikijs/shiki) package. It will set two CSS variables on the code block elements: - `--prosemirror-highlight`: sets text color - `--prosemirror-highlight-bg`: sets background color
@paramoptions - The options to configure the Shiki highlighter.@public
(),
) const editorconst editor: Editor<Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>> = createEditorcreateEditor<Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>>(options: EditorOptions<Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>>): Editor<Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>>
@public
({ extensionEditorOptions<Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>>.extension: Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>
The extension to use when creating the editor.
})

Priority is a 5-level enum that controls the order in which conflicting contributions resolve.

import { defineBasicExtensionfunction defineBasicExtension(): BasicExtension
Define a basic extension that includes some common functionality. You can copy this function and customize it to your needs. It's a combination of the following extension functions: - {@link defineDoc } - {@link defineText } - {@link defineParagraph } - {@link defineHeading } - {@link defineList } - {@link defineBlockquote } - {@link defineImage } - {@link defineHorizontalRule } - {@link defineHardBreak } - {@link defineTable } - {@link defineCodeBlock } - {@link defineItalic } - {@link defineBold } - {@link defineUnderline } - {@link defineStrike } - {@link defineCode } - {@link defineLink } - {@link defineBaseKeymap } - {@link defineBaseCommands } - {@link defineHistory } - {@link defineGapCursor } - {@link defineVirtualSelection } - {@link defineModClickPrevention }
@public
} from 'prosekit/basic'
import { Priority
type Priority = 0 | 1 | 2 | 3 | 4
const Priority: {
    readonly lowest: 0;
    readonly low: 1;
    readonly default: 2;
    readonly high: 3;
    readonly highest: 4;
}
ProseKit extension priority. There are five priority levels available: - `Priority.lowest` - `Priority.low` - `Priority.default` - `Priority.high` - `Priority.highest`
@example```ts import { withPriority, Priority } from 'prosekit/core' import { myExtension } from './my-extension.js' const myExtensionWithHighPriority = withPriority(myExtension, Priority.high) ```@public@example```ts import { withPriority, Priority } from 'prosekit/core' import { myExtension } from './my-extension.js' const myExtensionWithHighPriority = withPriority(myExtension, Priority.high) ```@public
, unionfunction union<const E extends readonly Extension[]>(...exts: E): Union<E> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as arguments or a single array containing multiple extensions.
@throwsIf no extensions are provided.@example```ts function defineFancyNodes() { return union( defineFancyParagraph(), defineFancyHeading(), ) } ```@example```ts function defineFancyNodes() { return union([ defineFancyParagraph(), defineFancyHeading(), ]) } ```@public
, withPriorityfunction withPriority<T extends Extension>(extension: T, priority: Priority): T
Return an new extension with the given priority.
@example```ts import { Priority, withPriority } from 'prosekit/core' const extension = withPriority(defineMyExtension(), Priority.high) ```@public
} from 'prosekit/core'
import { defineKeymapfunction defineKeymap(keymap: Keymap): PlainExtension
Adds a set of keybindings to the editor. Please read the [documentation](https://prosemirror.net/docs/ref/#keymap) for more details.
@public
} from 'prosekit/core'
const myKeymapconst myKeymap: PlainExtension = defineKeymapfunction defineKeymap(keymap: Keymap): PlainExtension
Adds a set of keybindings to the editor. Please read the [documentation](https://prosemirror.net/docs/ref/#keymap) for more details.
@public
({
'Mod-b': () => { consolevar console: Console.logConsole.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
('Custom bold behavior')
return true }, }) const extensionconst extension: Union<readonly [BasicExtension, PlainExtension]> = unionunion<readonly [BasicExtension, PlainExtension]>(exts_0: BasicExtension, exts_1: PlainExtension): Union<readonly [BasicExtension, PlainExtension]> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as arguments or a single array containing multiple extensions.
@throwsIf no extensions are provided.@example```ts function defineFancyNodes() { return union( defineFancyParagraph(), defineFancyHeading(), ) } ```@example```ts function defineFancyNodes() { return union([ defineFancyParagraph(), defineFancyHeading(), ]) } ```@public
(
defineBasicExtensionfunction defineBasicExtension(): BasicExtension
Define a basic extension that includes some common functionality. You can copy this function and customize it to your needs. It's a combination of the following extension functions: - {@link defineDoc } - {@link defineText } - {@link defineParagraph } - {@link defineHeading } - {@link defineList } - {@link defineBlockquote } - {@link defineImage } - {@link defineHorizontalRule } - {@link defineHardBreak } - {@link defineTable } - {@link defineCodeBlock } - {@link defineItalic } - {@link defineBold } - {@link defineUnderline } - {@link defineStrike } - {@link defineCode } - {@link defineLink } - {@link defineBaseKeymap } - {@link defineBaseCommands } - {@link defineHistory } - {@link defineGapCursor } - {@link defineVirtualSelection } - {@link defineModClickPrevention }
@public
(),
withPrioritywithPriority<PlainExtension>(extension: PlainExtension, priority: Priority): PlainExtension
Return an new extension with the given priority.
@example```ts import { Priority, withPriority } from 'prosekit/core' const extension = withPriority(defineMyExtension(), Priority.high) ```@public
(myKeymapconst myKeymap: PlainExtension, Priority
const Priority: {
    readonly lowest: 0;
    readonly low: 1;
    readonly default: 2;
    readonly high: 3;
    readonly highest: 4;
}
ProseKit extension priority. There are five priority levels available: - `Priority.lowest` - `Priority.low` - `Priority.default` - `Priority.high` - `Priority.highest`
@example```ts import { withPriority, Priority } from 'prosekit/core' import { myExtension } from './my-extension.js' const myExtensionWithHighPriority = withPriority(myExtension, Priority.high) ```@public@example```ts import { withPriority, Priority } from 'prosekit/core' import { myExtension } from './my-extension.js' const myExtensionWithHighPriority = withPriority(myExtension, Priority.high) ```@public
.highhigh: 3),
)

Use Priority.default (the default) unless you have a specific reason. withPriority returns a new extension; the original is left alone.

For one-off behavior, the easiest entry points are defineKeymap, defineCommands, and the per-event hooks like defineKeyDownHandler. For a full custom node or mark, see Custom Extensions.