Extensions
Every feature in ProseKit ships as an extension. Extensions are small, plain values you compose with union(...) and pass to createEditor.
The basic shape
Section titled “The basic shape”import { createEditor function createEditor<E extends Extension>(options: EditorOptions<E>): Editor<E>@public , union function 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 { defineDoc function defineDoc(): DocExtension@public } from 'prosekit/extensions/doc'
import { defineParagraph function 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 { defineText function defineText(): TextExtension@public } from 'prosekit/extensions/text'
const extension const extension: Union<readonly [DocExtension, TextExtension, ParagraphExtension]> = union union<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 (
defineDoc function defineDoc(): DocExtension@public (),
defineText function defineText(): TextExtension@public (),
defineParagraph function 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 editor const editor: Editor<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>> = createEditor createEditor<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>>(options: EditorOptions<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>>): Editor<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>>@public ({ extension EditorOptions<Union<readonly [DocExtension, TextExtension, ParagraphExtension]>>.extension: Union<readonly [DocExtension, TextExtension, ParagraphExtension]>The extension to use when creating the editor. })Per-feature define* factories
Section titled “Per-feature define* factories”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
Section titled “defineBasicExtension”defineBasicExtension is a ready-made bundle that's identical to:
import { defineBaseCommands function defineBaseCommands(): BaseCommandsExtensionAdd some base commands@public , defineBaseKeymap function defineBaseKeymap({ priority, preferBlockSelection, }?: BaseKeymapOptions): BaseKeymapExtensionDefines some basic key bindings.@paramoptions@public , defineHistory function defineHistory({ depth, newGroupDelay, }?: HistoryOptions): HistoryExtensionAdd undo/redo history to the editor.@paramoptions@public , union function 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 { defineBlockquote function defineBlockquote(): BlockquoteExtension@public } from 'prosekit/extensions/blockquote'
import { defineBold function defineBold(): BoldExtension@public } from 'prosekit/extensions/bold'
import { defineCode function defineCode(): CodeExtension@public } from 'prosekit/extensions/code'
import { defineCodeBlock function defineCodeBlock(): CodeBlockExtensionAdds `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 { defineDoc function defineDoc(): DocExtension@public } from 'prosekit/extensions/doc'
import { defineGapCursor function defineGapCursor(): GapCursorExtensionCapture 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 { defineHardBreak function defineHardBreak(): HardBreakExtension@public } from 'prosekit/extensions/hard-break'
import { defineHeading function defineHeading(): HeadingExtension@public } from 'prosekit/extensions/heading'
import { defineHorizontalRule function defineHorizontalRule(): HorizontalRuleExtension@public } from 'prosekit/extensions/horizontal-rule'
import { defineImage function defineImage(): ImageExtension@public } from 'prosekit/extensions/image'
import { defineItalic function defineItalic(): ItalicExtension@public } from 'prosekit/extensions/italic'
import { defineLink function defineLink(): LinkExtension@public } from 'prosekit/extensions/link'
import { defineList function defineList(): ListExtension@public } from 'prosekit/extensions/list'
import { defineModClickPrevention function defineModClickPrevention(): ModClickPreventionExtensionBy 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 { defineParagraph function 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 { defineStrike function defineStrike(): StrikeExtension@public } from 'prosekit/extensions/strike'
import { defineTable function defineTable(): TableExtension@public } from 'prosekit/extensions/table'
import { defineText function defineText(): TextExtension@public } from 'prosekit/extensions/text'
import { defineUnderline function defineUnderline(): UnderlineExtension@public } from 'prosekit/extensions/underline'
import { defineVirtualSelection function defineVirtualSelection(): VirtualSelectionExtensionShows 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 defineBasicExtension function defineBasicExtension(): Union<readonly [DocExtension, TextExtension, ParagraphExtension, HeadingExtension, ListExtension, BlockquoteExtension, ImageExtension, HorizontalRuleExtension, HardBreakExtension, TableExtension, CodeBlockExtension, ItalicExtension, BoldExtension, UnderlineExtension, ... 8 more ..., PlainExtension]> () {
return union union<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
defineDoc function defineDoc(): DocExtension@public (),
defineText function defineText(): TextExtension@public (),
defineParagraph function 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. (),
defineHeading function defineHeading(): HeadingExtension@public (),
defineList function defineList(): ListExtension@public (),
defineBlockquote function defineBlockquote(): BlockquoteExtension@public (),
defineImage function defineImage(): ImageExtension@public (),
defineHorizontalRule function defineHorizontalRule(): HorizontalRuleExtension@public (),
defineHardBreak function defineHardBreak(): HardBreakExtension@public (),
defineTable function defineTable(): TableExtension@public (),
defineCodeBlock function defineCodeBlock(): CodeBlockExtensionAdds `codeBlock` nodes to the editor. This includes the following extensions:
-
{@link
defineCodeBlockSpec
}
-
{@link
defineCodeBlockInputRule
}
-
{@link
defineCodeBlockEnterRule
}
-
{@link
defineCodeBlockKeymap
}
-
{@link
defineCodeBlockCommands
}
.@public (),
// Marks
defineItalic function defineItalic(): ItalicExtension@public (),
defineBold function defineBold(): BoldExtension@public (),
defineUnderline function defineUnderline(): UnderlineExtension@public (),
defineStrike function defineStrike(): StrikeExtension@public (),
defineCode function defineCode(): CodeExtension@public (),
defineLink function defineLink(): LinkExtension@public (),
// Others
defineBaseKeymap function defineBaseKeymap({ priority, preferBlockSelection, }?: BaseKeymapOptions): BaseKeymapExtensionDefines some basic key bindings.@paramoptions@public (),
defineBaseCommands function defineBaseCommands(): BaseCommandsExtensionAdd some base commands@public (),
defineHistory function defineHistory({ depth, newGroupDelay, }?: HistoryOptions): HistoryExtensionAdd undo/redo history to the editor.@paramoptions@public (),
defineGapCursor function defineGapCursor(): GapCursorExtensionCapture 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 (),
defineVirtualSelection function defineVirtualSelection(): VirtualSelectionExtensionShows 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 (),
defineModClickPrevention function defineModClickPrevention(): ModClickPreventionExtensionBy 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.
Extending an existing bundle
Section titled “Extending an existing bundle”You can union a bundle with extra extensions to add features:
import { defineBasicExtension function defineBasicExtension(): BasicExtensionDefine 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 { createEditor function createEditor<E extends Extension>(options: EditorOptions<E>): Editor<E>@public , union function 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 { defineCodeBlockShiki function defineCodeBlockShiki({ nodeTypes, themes, langs, ...rest }?: CodeBlockShikiOptions): ExtensionAdds 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 extension const extension: Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]> = union union<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 (
defineBasicExtension function defineBasicExtension(): BasicExtensionDefine 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 (),
defineCodeBlockShiki function defineCodeBlockShiki({ nodeTypes, themes, langs, ...rest }?: CodeBlockShikiOptions): ExtensionAdds 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 editor const editor: Editor<Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>> = createEditor createEditor<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 ({ extension EditorOptions<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
Section titled “Priority”Priority is a 5-level enum that controls the order in which conflicting contributions resolve.
import { defineBasicExtension function defineBasicExtension(): BasicExtensionDefine 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 , union function 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 , withPriority function withPriority<T extends Extension>(extension: T, priority: Priority): TReturn 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 { defineKeymap function defineKeymap(keymap: Keymap): PlainExtensionAdds 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 myKeymap const myKeymap: PlainExtension = defineKeymap function defineKeymap(keymap: Keymap): PlainExtensionAdds a set of keybindings to the editor. Please read the
[documentation](https://prosemirror.net/docs/ref/#keymap) for more details.@public ({
'Mod-b': () => {
console var console: Console .log Console.log(...data: any[]): voidThe **`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 extension const extension: Union<readonly [BasicExtension, PlainExtension]> = union union<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 (
defineBasicExtension function defineBasicExtension(): BasicExtensionDefine 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 (),
withPriority withPriority<PlainExtension>(extension: PlainExtension, priority: Priority): PlainExtensionReturn an new extension with the given priority.@example```ts
import { Priority, withPriority } from 'prosekit/core'
const extension = withPriority(defineMyExtension(), Priority.high)
```@public (myKeymap const 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 .high high: 3 ),
)Use Priority.default (the default) unless you have a specific reason. withPriority returns a new extension; the original is left alone.
Defining your own extension
Section titled “Defining your own extension”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.
See also
Section titled “See also”- Schema: defining your own nodes and marks.
- Commands: running commands and binding keys.
prosekit/corereferenceprosekit/extensionsreference