> ## 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

> Learn how to create custom extensions to add new functionality to Tiptap

# 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.

<CodeGroup>
  ```typescript Extension API theme={null}
  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
      ]
    },
  })
  ```
</CodeGroup>

## Creating a Simple Extension

Let's create a simple extension that replaces emoticons with emojis as you type.

<CodeGroup>
  ```typescript SmilieReplacer Extension theme={null}
  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: '¯\\_(ツ)_/¯' }),
      ]
    },
  })
  ```
</CodeGroup>

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.

<CodeGroup>
  ```typescript ColorHighlighter Extension theme={null}
  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)
            },
          },
        }),
      ]
    },
  })
  ```
</CodeGroup>

Source: `demos/src/Examples/Savvy/React/ColorHighlighter.ts:1`

## Extension Configuration

### Adding Options

Extensions can accept configuration options that customize their behavior.

<CodeGroup>
  ```typescript Extension with Options theme={null}
  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)
        },
      }
    },
  })
  ```
</CodeGroup>

### Configuring Extensions

<CodeGroup>
  ```typescript Configure on Use theme={null}
  import { Editor } from '@tiptap/core'
  import { MyExtension } from './my-extension'

  const editor = new Editor({
    extensions: [
      MyExtension.configure({
        prefix: 'custom',
        maxLength: 200,
      }),
    ],
  })
  ```
</CodeGroup>

## Extension Storage

Extensions can maintain their own state using storage.

<CodeGroup>
  ```typescript Extension with Storage theme={null}
  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
        },
      }
    },
  })
  ```
</CodeGroup>

## Lifecycle Hooks

Extensions can hook into various editor lifecycle events.

<CodeGroup>
  ```typescript Extension Lifecycle theme={null}
  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')
    },
  })
  ```
</CodeGroup>

Source: `packages/core/src/Extendable.ts:341`

## Keyboard Shortcuts

Add custom keyboard shortcuts to your extension.

<CodeGroup>
  ```typescript Keyboard Shortcuts theme={null}
  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(),
          ])
        },
      }
    },
  })
  ```
</CodeGroup>

Source: `packages/core/src/Extendable.ts:133`

## Global Attributes

Extensions can add attributes to other nodes or marks.

<CodeGroup>
  ```typescript Global Attributes theme={null}
  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 })
          )
        },
      }
    },
  })
  ```
</CodeGroup>

Source: `packages/core/src/Extendable.ts:79`

## Priority

Control the order in which extensions are loaded and executed.

<CodeGroup>
  ```typescript Extension Priority theme={null}
  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
  })
  ```
</CodeGroup>

Source: `packages/core/src/Extendable.ts:50`

## Extending Existing Extensions

You can extend existing extensions to customize their behavior.

<CodeGroup>
  ```typescript Extend Extension theme={null}
  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: '🔥 ' }),
      ]
    },
  })
  ```
</CodeGroup>

Source: `packages/core/src/Extension.ts:35`

<Note>
  Extensions are ideal for adding editor-wide functionality. Use Nodes for block content and Marks for inline formatting.
</Note>

## Next Steps

<CardGroup cols={2}>
  <Card title="Custom Nodes" icon="cube" href="/guides/custom-nodes">
    Learn how to create custom block content
  </Card>

  <Card title="Custom Marks" icon="highlighter" href="/guides/custom-marks">
    Create custom inline formatting
  </Card>
</CardGroup>
