Documentation Index Fetch the complete documentation index at: https://mintlify.com/ueberdosis/tiptap/llms.txt
Use this file to discover all available pages before exploring further.
Custom Extensions
Extensions are the building blocks of Tiptap. They allow you to add new functionality to the editor without modifying nodes or marks. Extensions are perfect for adding editor-wide features like commands, keyboard shortcuts, or plugins.
Understanding Extensions
The Extension class is the base class for all extensions in Tiptap. It provides a rich API for extending the editor’s functionality.
import { Extension } from '@tiptap/core'
export const MyExtension = Extension . create ({
name: 'myExtension' ,
addOptions () {
return {
// Default options
}
},
addCommands () {
return {
// Custom commands
}
},
addKeyboardShortcuts () {
return {
// Keyboard shortcuts
}
},
addProseMirrorPlugins () {
return [
// ProseMirror plugins
]
},
})
Creating a Simple Extension
Let’s create a simple extension that replaces emoticons with emojis as you type.
import { Extension , textInputRule } from '@tiptap/core'
export const SmilieReplacer = Extension . create ({
name: 'smilieReplacer' ,
addInputRules () {
return [
textInputRule ({ find: /:- \) $ / , replace: '🙂 ' }),
textInputRule ({ find: /:D $ / , replace: '😃 ' }),
textInputRule ({ find: /;- \) $ / , replace: '😉 ' }),
textInputRule ({ find: /:- \( $ / , replace: '😞 ' }),
textInputRule ({ find: /<3 $ / , replace: '❤️ ' }),
textInputRule ({ find: / \/ shrug $ / , replace: '¯ \\ _(ツ)_/¯' }),
]
},
})
Source: demos/src/Examples/Savvy/React/SmilieReplacer.ts:1
Extension with ProseMirror Plugins
Here’s a more advanced extension that uses ProseMirror plugins to highlight color codes in the editor.
ColorHighlighter Extension
import { Extension } from '@tiptap/core'
import { Plugin } from '@tiptap/pm/state'
import findColors from './findColors'
export const ColorHighlighter = Extension . create ({
name: 'colorHighlighter' ,
addProseMirrorPlugins () {
return [
new Plugin ({
state: {
init ( _ , { doc }) {
return findColors ( doc )
},
apply ( transaction , oldState ) {
return transaction . docChanged
? findColors ( transaction . doc )
: oldState
},
},
props: {
decorations ( state ) {
return this . getState ( state )
},
},
}),
]
},
})
Source: demos/src/Examples/Savvy/React/ColorHighlighter.ts:1
Extension Configuration
Adding Options
Extensions can accept configuration options that customize their behavior.
import { Extension } from '@tiptap/core'
interface MyExtensionOptions {
prefix : string
maxLength : number
}
export const MyExtension = Extension . create < MyExtensionOptions >({
name: 'myExtension' ,
addOptions () {
return {
prefix: 'default' ,
maxLength: 100 ,
}
},
addCommands () {
return {
insertPrefix : () => ({ commands }) => {
return commands . insertContent ( this . options . prefix )
},
}
},
})
Configuring Extensions
import { Editor } from '@tiptap/core'
import { MyExtension } from './my-extension'
const editor = new Editor ({
extensions: [
MyExtension . configure ({
prefix: 'custom' ,
maxLength: 200 ,
}),
],
})
Extension Storage
Extensions can maintain their own state using storage.
import { Extension } from '@tiptap/core'
interface MyStorage {
count : number
items : string []
}
export const MyExtension = Extension . create <{}, MyStorage >({
name: 'myExtension' ,
addStorage () {
return {
count: 0 ,
items: [],
}
},
onCreate () {
this . storage . count = 0
},
addCommands () {
return {
incrementCount : () => ({ editor }) => {
this . storage . count ++
return true
},
addItem : ( item : string ) => ({ editor }) => {
this . storage . items . push ( item )
return true
},
}
},
})
Lifecycle Hooks
Extensions can hook into various editor lifecycle events.
import { Extension } from '@tiptap/core'
export const MyExtension = Extension . create ({
name: 'myExtension' ,
onBeforeCreate () {
// Before the editor is created
console . log ( 'Before create' )
},
onCreate () {
// Editor is ready
console . log ( 'Editor created' )
},
onUpdate () {
// Content has changed
console . log ( 'Content updated' )
},
onSelectionUpdate () {
// Selection has changed
console . log ( 'Selection changed' )
},
onTransaction ({ transaction }) {
// On every transaction
console . log ( 'Transaction:' , transaction )
},
onFocus () {
// Editor gained focus
console . log ( 'Editor focused' )
},
onBlur () {
// Editor lost focus
console . log ( 'Editor blurred' )
},
onDestroy () {
// Editor is being destroyed
console . log ( 'Editor destroyed' )
},
})
Source: packages/core/src/Extendable.ts:341
Keyboard Shortcuts
Add custom keyboard shortcuts to your extension.
import { Extension } from '@tiptap/core'
export const MyExtension = Extension . create ({
name: 'myExtension' ,
addKeyboardShortcuts () {
return {
// Mod is Cmd on Mac, Ctrl on Windows/Linux
'Mod-k' : () => {
console . log ( 'Mod-k pressed' )
return true
},
// Multiple modifiers
'Mod-Shift-z' : () => {
this . editor . commands . redo ()
return true
},
// Handle Enter key
'Enter' : () => {
return this . editor . commands . first ([
() => this . editor . commands . newlineInCode (),
() => this . editor . commands . createParagraphNear (),
])
},
}
},
})
Source: packages/core/src/Extendable.ts:133
Global Attributes
Extensions can add attributes to other nodes or marks.
import { Extension } from '@tiptap/core'
export const TextAlign = Extension . create ({
name: 'textAlign' ,
addOptions () {
return {
types: [ 'heading' , 'paragraph' ],
alignments: [ 'left' , 'center' , 'right' , 'justify' ],
defaultAlignment: 'left' ,
}
},
addGlobalAttributes () {
return [
{
types: this . options . types ,
attributes: {
textAlign: {
default: this . options . defaultAlignment ,
parseHTML : element => element . style . textAlign || this . options . defaultAlignment ,
renderHTML : attributes => {
if ( attributes . textAlign === this . options . defaultAlignment ) {
return {}
}
return { style: `text-align: ${ attributes . textAlign } ` }
},
},
},
},
]
},
addCommands () {
return {
setTextAlign : ( alignment : string ) => ({ commands }) => {
if ( ! this . options . alignments . includes ( alignment )) {
return false
}
return this . options . types . every ( type =>
commands . updateAttributes ( type , { textAlign: alignment })
)
},
}
},
})
Source: packages/core/src/Extendable.ts:79
Priority
Control the order in which extensions are loaded and executed.
import { Extension } from '@tiptap/core'
export const MyExtension = Extension . create ({
name: 'myExtension' ,
priority: 1000 , // Higher priority loads earlier (default: 100)
// This extension will take precedence over lower-priority extensions
})
Source: packages/core/src/Extendable.ts:50
Extending Existing Extensions
You can extend existing extensions to customize their behavior.
import { Extension } from '@tiptap/core'
import { SmilieReplacer } from './smilie-replacer'
export const CustomSmilieReplacer = SmilieReplacer . extend ({
addInputRules () {
return [
// Keep parent rules
... this . parent ?.() || [],
// Add new rules
textInputRule ({ find: /:wave: $ / , replace: '👋 ' }),
textInputRule ({ find: /:fire: $ / , replace: '🔥 ' }),
]
},
})
Source: packages/core/src/Extension.ts:35
Extensions are ideal for adding editor-wide functionality. Use Nodes for block content and Marks for inline formatting.
Next Steps
Custom Nodes Learn how to create custom block content
Custom Marks Create custom inline formatting