Using Extensions
Extensions are at the heart of ProseKit’s flexibility and power. They allow you to add functionality to your editor in a modular way, making it easy to build exactly the editing experience you need.
What are extensions?
Section titled “What are extensions?”Extensions in ProseKit are modular pieces of functionality that you can add to your editor. They can provide:
- Nodes (paragraphs, headings, lists, code blocks, etc.)
- Marks (bold, italic, underline, etc.)
- Commands (functions that modify the document)
- Keyboard shortcuts
- Input rules (automatic transformations as you type)
- Custom behaviors and much more
Basic extension usage
Section titled “Basic extension usage”ProseKit provides a defineBasicExtension()
function that includes the most common features:
import { defineBasicExtension function 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
defineDropCursor
}
-
{@link
defineGapCursor
}
-
{@link
defineVirtualSelection
}
-
{@link
defineModClickPrevention
} } from 'prosekit/basic'
import { createEditor function createEditor<E extends Extension>(options: EditorOptions<E>): Editor<E>
} from 'prosekit/core'
// Create an editor with the extension
const editor const editor: Editor<BasicExtension>
= createEditor createEditor<BasicExtension>(options: EditorOptions<BasicExtension>): Editor<BasicExtension>
({ extension EditorOptions<BasicExtension>.extension: BasicExtension
The extension to use when creating the editor. : defineBasicExtension function 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
defineDropCursor
}
-
{@link
defineGapCursor
}
-
{@link
defineVirtualSelection
}
-
{@link
defineModClickPrevention
} () })
Composing extensions with union
Section titled “Composing extensions with union”A key concept in ProseKit is that all extensions are composed of other extensions using the union
function. This composability lets you create complex functionality by combining simpler building blocks.
For example, defineBasicExtension
is simply a composition of many smaller extensions:
import {
defineBaseCommands function defineBaseCommands(): BaseCommandsExtension
Add some base commands ,
defineBaseKeymap function defineBaseKeymap(options?: {
priority?: Priority;
}): BaseKeymapExtension
Defines some basic key bindings. ,
defineHistory function defineHistory({ depth, newGroupDelay, }?: HistoryOptions): HistoryExtension
Add undo/redo history to the editor. ,
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. ,
} from 'prosekit/core'
import { defineBlockquote function defineBlockquote(): BlockquoteExtension
} from 'prosekit/extensions/blockquote'
import { defineBold function defineBold(): BoldExtension
} from 'prosekit/extensions/bold'
import { defineCode function defineCode(): CodeExtension
} from 'prosekit/extensions/code'
import { defineCodeBlock function defineCodeBlock(): CodeBlockExtension
Adds `codeBlock` nodes to the editor. This includes the following extensions:
-
{@link
defineCodeBlockSpec
}
-
{@link
defineCodeBlockInputRule
}
-
{@link
defineCodeBlockEnterRule
}
-
{@link
defineCodeBlockKeymap
}
-
{@link
defineCodeBlockCommands
}
. } from 'prosekit/extensions/code-block'
import { defineDoc function defineDoc(): DocExtension
} from 'prosekit/extensions/doc'
import { defineDropCursor function defineDropCursor(options?: DropCursorOptions): DropCursorExtension
Show up a decoration at the drop position when something is dragged over the editor.
See [prosemirror-dropcursor](https://github.com/ProseMirror/prosemirror-dropcursor) for more information. } from 'prosekit/extensions/drop-cursor'
import { defineGapCursor function 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. } from 'prosekit/extensions/gap-cursor'
import { defineHeading function defineHeading(): HeadingExtension
} from 'prosekit/extensions/heading'
import { defineHorizontalRule function defineHorizontalRule(): HorizontalRuleExtension
} from 'prosekit/extensions/horizontal-rule'
import { defineImage function defineImage(): ImageExtension
} from 'prosekit/extensions/image'
import { defineItalic function defineItalic(): ItalicExtension
} from 'prosekit/extensions/italic'
import { defineLink function defineLink(): LinkExtension
} from 'prosekit/extensions/link'
import { defineList function defineList(): ListExtension
} from 'prosekit/extensions/list'
import { defineModClickPrevention function defineModClickPrevention(): ModClickPreventionExtension
By default, clicking a node while holding the mod key will select the node. This
extension disables that behavior. } from 'prosekit/extensions/mod-click-prevention'
import { defineParagraph function defineParagraph(): ParagraphExtension
} from 'prosekit/extensions/paragraph'
import { defineStrike function defineStrike(): StrikeExtension
} from 'prosekit/extensions/strike'
import { defineTable function defineTable(): TableExtension
} from 'prosekit/extensions/table'
import { defineText function defineText(): TextExtension
} from 'prosekit/extensions/text'
import { defineUnderline function defineUnderline(): UnderlineExtension
} from 'prosekit/extensions/underline'
import { defineVirtualSelection function 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. } from 'prosekit/extensions/virtual-selection'
function defineBasicExtension function defineBasicExtension(): Union<readonly [DocExtension, TextExtension, ParagraphExtension, HeadingExtension, ListExtension, ... 17 more ..., PlainExtension]>
() {
return union union<readonly [DocExtension, TextExtension, ParagraphExtension, HeadingExtension, ListExtension, ... 17 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: TableExtension, exts_9: CodeBlockExtension, exts_10: ItalicExtension, exts_11: BoldExtension, exts_12: UnderlineExtension, exts_13: StrikeExtension, exts_14: CodeExtension, exts_15: LinkExtension, exts_16: PlainExtension, exts_17: BaseCommandsExtension, exts_18: HistoryExtension, exts_19: PlainExtension, 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. (
// Nodes
defineDoc function defineDoc(): DocExtension
(),
defineText function defineText(): TextExtension
(),
defineParagraph function defineParagraph(): ParagraphExtension
(),
defineHeading function defineHeading(): HeadingExtension
(),
defineList function defineList(): ListExtension
(),
defineBlockquote function defineBlockquote(): BlockquoteExtension
(),
defineImage function defineImage(): ImageExtension
(),
defineHorizontalRule function defineHorizontalRule(): HorizontalRuleExtension
(),
defineTable function defineTable(): TableExtension
(),
defineCodeBlock function defineCodeBlock(): CodeBlockExtension
Adds `codeBlock` nodes to the editor. This includes the following extensions:
-
{@link
defineCodeBlockSpec
}
-
{@link
defineCodeBlockInputRule
}
-
{@link
defineCodeBlockEnterRule
}
-
{@link
defineCodeBlockKeymap
}
-
{@link
defineCodeBlockCommands
}
. (),
// Marks
defineItalic function defineItalic(): ItalicExtension
(),
defineBold function defineBold(): BoldExtension
(),
defineUnderline function defineUnderline(): UnderlineExtension
(),
defineStrike function defineStrike(): StrikeExtension
(),
defineCode function defineCode(): CodeExtension
(),
defineLink function defineLink(): LinkExtension
(),
// Others
defineBaseKeymap function defineBaseKeymap(options?: {
priority?: Priority;
}): BaseKeymapExtension
Defines some basic key bindings. (),
defineBaseCommands function defineBaseCommands(): BaseCommandsExtension
Add some base commands (),
defineHistory function defineHistory({ depth, newGroupDelay, }?: HistoryOptions): HistoryExtension
Add undo/redo history to the editor. (),
defineDropCursor function defineDropCursor(options?: DropCursorOptions): DropCursorExtension
Show up a decoration at the drop position when something is dragged over the editor.
See [prosemirror-dropcursor](https://github.com/ProseMirror/prosemirror-dropcursor) for more information. (),
defineGapCursor function 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. (),
defineVirtualSelection function 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. (),
defineModClickPrevention function defineModClickPrevention(): ModClickPreventionExtension
By default, clicking a node while holding the mod key will select the node. This
extension disables that behavior. (),
)
}
This compositional pattern allows you to build on existing extensions and add exactly the features you need. For example, if you want all the functionality of the basic extension plus syntax highlighting for code blocks, you can simply combine them:
import { defineBasicExtension function 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
defineDropCursor
}
-
{@link
defineGapCursor
}
-
{@link
defineVirtualSelection
}
-
{@link
defineModClickPrevention
} } from 'prosekit/basic'
import {
createEditor function createEditor<E extends Extension>(options: EditorOptions<E>): Editor<E>
,
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. ,
} from 'prosekit/core'
import { defineCodeBlockShiki function defineCodeBlockShiki({ 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 } from 'prosekit/extensions/code-block'
function defineMyExtension function defineMyExtension(): Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>
() {
return union union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>(exts_0: BasicExtension, exts_1: Extension<ExtensionTyping<any, any, any>>): Union<...> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as
arguments or a single array containing multiple extensions. (
defineBasicExtension function 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
defineDropCursor
}
-
{@link
defineGapCursor
}
-
{@link
defineVirtualSelection
}
-
{@link
defineModClickPrevention
} (),
defineCodeBlockShiki function defineCodeBlockShiki({ 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 (),
)
}
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<...>
({ 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. : defineMyExtension function defineMyExtension(): Union<readonly [BasicExtension, Extension<ExtensionTyping<any, any, any>>]>
() })
Customizing extensions
Section titled “Customizing extensions”Since each extension is composed of smaller parts, you can easily customize functionality by picking exactly which components you want. For example, the defineCode()
extension defines a mark spec, commands, keyboard shortcut, and input rule.
If you want to keep everything except the keyboard shortcut, you can inspect the source code of the defineCode()
extension, and create a custom version:
import { 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. } from 'prosekit/core'
import {
defineCodeCommands function defineCodeCommands(): CodeCommandsExtension
,
defineCodeInputRule function defineCodeInputRule(): PlainExtension
,
defineCodeSpec function defineCodeSpec(): CodeSpecExtension
,
// Omitting defineCodeKeymap
} from 'prosekit/extensions/code'
function defineMyCode function defineMyCode(): Union<readonly [CodeSpecExtension, CodeCommandsExtension, PlainExtension]>
() {
return union union<readonly [CodeSpecExtension, CodeCommandsExtension, PlainExtension]>(exts_0: CodeSpecExtension, exts_1: CodeCommandsExtension, exts_2: PlainExtension): Union<...> (+1 overload)
Merges multiple extensions into one. You can pass multiple extensions as
arguments or a single array containing multiple extensions. (
defineCodeSpec function defineCodeSpec(): CodeSpecExtension
(),
defineCodeCommands function defineCodeCommands(): CodeCommandsExtension
(),
defineCodeInputRule function defineCodeInputRule(): PlainExtension
(),
// No keyboard shortcut
)
}