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

# History (UndoRedo)

> Add undo and redo functionality to track and revert changes

The History extension (also known as UndoRedo) provides undo and redo functionality for your editor. It tracks changes and allows users to step backward and forward through their edit history.

<Warning>
  If you're using the `@tiptap/extension-collaboration` package, do not use this extension. The Collaboration extension includes its own history implementation that's designed to work in collaborative environments.
</Warning>

## Installation

The History extension is included in the `@tiptap/extensions` package and is also part of the StarterKit.

<CodeGroup>
  ```bash npm theme={null}
  npm install @tiptap/extensions
  ```

  ```bash yarn theme={null}
  yarn add @tiptap/extensions
  ```

  ```bash pnpm theme={null}
  pnpm add @tiptap/extensions
  ```
</CodeGroup>

## Basic Usage

### Included in StarterKit

The History extension is included by default when using StarterKit:

```javascript theme={null}
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'

const editor = new Editor({
  extensions: [
    StarterKit, // History is included
  ],
})
```

### Standalone Usage

```javascript theme={null}
import { Editor } from '@tiptap/core'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import { UndoRedo } from '@tiptap/extensions/undo-redo'

const editor = new Editor({
  extensions: [
    Document,
    Paragraph,
    Text,
    UndoRedo,
  ],
})
```

### Custom Configuration

```javascript theme={null}
import StarterKit from '@tiptap/starter-kit'

const editor = new Editor({
  extensions: [
    StarterKit.configure({
      history: {
        depth: 50,
        newGroupDelay: 1000,
      },
    }),
  ],
})
```

## Configuration Options

<ParamField path="depth" type="number">
  The amount of history events that are collected before the oldest events are discarded. This prevents the history from growing indefinitely.

  **Default:** `100`

  ```javascript theme={null}
  UndoRedo.configure({
    depth: 50, // Keep only last 50 changes
  })
  ```
</ParamField>

<ParamField path="newGroupDelay" type="number">
  The delay in milliseconds between changes after which a new history group should be started. Changes that occur within this delay are grouped together as a single undo/redo step.

  **Default:** `500`

  ```javascript theme={null}
  UndoRedo.configure({
    newGroupDelay: 1000, // Group changes within 1 second
  })
  ```
</ParamField>

## Commands

<ParamField path="undo" type="command">
  Undo recent changes.

  **Keyboard shortcuts:** `Cmd/Ctrl + Z`, `Cmd/Ctrl + я` (Russian layout)

  ```javascript theme={null}
  editor.commands.undo()
  ```
</ParamField>

<ParamField path="redo" type="command">
  Reapply reverted changes.

  **Keyboard shortcuts:**

  * `Cmd/Ctrl + Shift + Z`
  * `Cmd/Ctrl + Y`
  * `Cmd/Ctrl + Shift + я` (Russian layout)

  ```javascript theme={null}
  editor.commands.redo()
  ```
</ParamField>

## Keyboard Shortcuts

| Shortcut               | Command | Description                    |
| ---------------------- | ------- | ------------------------------ |
| `Cmd/Ctrl + Z`         | undo    | Undo the last change           |
| `Cmd/Ctrl + Shift + Z` | redo    | Redo the last undone change    |
| `Cmd/Ctrl + Y`         | redo    | Redo the last undone change    |
| `Cmd/Ctrl + я`         | undo    | Undo (Russian keyboard layout) |
| `Cmd/Ctrl + Shift + я` | redo    | Redo (Russian keyboard layout) |

## Advanced Examples

### Custom Undo/Redo Buttons

```javascript theme={null}
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'

const editor = new Editor({
  extensions: [StarterKit],
})

// Create undo button
const undoButton = document.querySelector('#undo')
undoButton.addEventListener('click', () => {
  editor.commands.undo()
})

// Create redo button
const redoButton = document.querySelector('#redo')
redoButton.addEventListener('click', () => {
  editor.commands.redo()
})

// Update button states
editor.on('transaction', () => {
  undoButton.disabled = !editor.can().undo()
  redoButton.disabled = !editor.can().redo()
})
```

### React Component with Undo/Redo

```tsx theme={null}
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { useState, useEffect } from 'react'

function Editor() {
  const editor = useEditor({
    extensions: [StarterKit],
    content: '<p>Start typing...</p>',
  })
  
  const [canUndo, setCanUndo] = useState(false)
  const [canRedo, setCanRedo] = useState(false)
  
  useEffect(() => {
    if (!editor) return
    
    const updateHistoryState = () => {
      setCanUndo(editor.can().undo())
      setCanRedo(editor.can().redo())
    }
    
    editor.on('transaction', updateHistoryState)
    updateHistoryState()
    
    return () => {
      editor.off('transaction', updateHistoryState)
    }
  }, [editor])
  
  return (
    <div>
      <div className="toolbar">
        <button 
          onClick={() => editor.commands.undo()} 
          disabled={!canUndo}
        >
          Undo
        </button>
        <button 
          onClick={() => editor.commands.redo()} 
          disabled={!canRedo}
        >
          Redo
        </button>
      </div>
      <EditorContent editor={editor} />
    </div>
  )
}
```

### Shorter History Depth for Memory Efficiency

```javascript theme={null}
const editor = new Editor({
  extensions: [
    StarterKit.configure({
      history: {
        depth: 20, // Keep only 20 steps instead of default 100
      },
    }),
  ],
})
```

### Faster Grouping for Rapid Edits

```javascript theme={null}
// Useful for live coding editors or fast-paced note-taking
const editor = new Editor({
  extensions: [
    StarterKit.configure({
      history: {
        newGroupDelay: 200, // Group changes within 200ms
      },
    }),
  ],
})
```

### Disable History in StarterKit

If you want to use the Collaboration extension instead:

```javascript theme={null}
import StarterKit from '@tiptap/starter-kit'
import Collaboration from '@tiptap/extension-collaboration'
import * as Y from 'yjs'

const ydoc = new Y.Doc()

const editor = new Editor({
  extensions: [
    StarterKit.configure({
      history: false, // Disable default history
    }),
    Collaboration.configure({
      document: ydoc,
    }),
  ],
})
```

### Check if Undo/Redo is Available

```javascript theme={null}
// Check if undo is possible
if (editor.can().undo()) {
  console.log('Undo is available')
  editor.commands.undo()
}

// Check if redo is possible
if (editor.can().redo()) {
  console.log('Redo is available')
  editor.commands.redo()
}
```

### Vue Component Example

```vue theme={null}
<template>
  <div>
    <div class="toolbar">
      <button @click="undo" :disabled="!canUndo">
        Undo
      </button>
      <button @click="redo" :disabled="!canRedo">
        Redo
      </button>
    </div>
    <editor-content :editor="editor" />
  </div>
</template>

<script>
import { Editor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'

export default {
  components: {
    EditorContent,
  },
  data() {
    return {
      editor: null,
      canUndo: false,
      canRedo: false,
    }
  },
  mounted() {
    this.editor = new Editor({
      extensions: [StarterKit],
      content: '<p>Start typing...</p>',
      onTransaction: () => {
        this.canUndo = this.editor.can().undo()
        this.canRedo = this.editor.can().redo()
      },
    })
  },
  beforeUnmount() {
    this.editor.destroy()
  },
  methods: {
    undo() {
      this.editor.commands.undo()
    },
    redo() {
      this.editor.commands.redo()
    },
  },
}
</script>
```

## How History Works

The History extension groups changes based on time. When you type continuously, all changes within the `newGroupDelay` window are grouped together as a single undo step. This creates a natural editing experience:

* Typing continuously: All text entered within 500ms is one undo step
* Pausing then typing: Creates a new undo step
* Each formatting change: Usually a separate undo step
* Large operations: Typically a single undo step

## Source Code

View the source code on GitHub:

* [Extension](https://github.com/ueberdosis/tiptap/tree/main/packages/extensions/src/undo-redo/undo-redo.ts:46)
