---
title: "How to upgrade Tiptap v2 to v3"
description: "Upgrade your Tiptap v2 project to version 3. Learn about the changes and how to migrate your project."
canonical_url: "https://tiptap.dev/docs/guides/upgrade-tiptap-v2"
---

# How to upgrade Tiptap v2 to v3

Upgrade your Tiptap v2 project to version 3. Learn about the changes and how to migrate your project.

Tiptap v3 is a major update with breaking changes. This guide will help you upgrade your Tiptap v2 project to version 3.

## Breaking Changes

### Package Changes

- UMD builds have been removed (now using tsup)

Some packages may have been removed or renamed, so you may need to update your imports and dependencies. Here are some common changes:

```diff
Table packages
- import Table from '@tiptap/extension-table'
- import TableRow from '@tiptap/extension-table-row'
- import TableCell from '@tiptap/extension-table-cell'
- import TableHeader from '@tiptap/extension-table-header'
+ import { Table, TableRow, TableCell, TableHeader } from '@tiptap/extension-table'

List packages
- import BulletList from '@tiptap/extension-bullet-list'
- import OrderedList from '@tiptap/extension-ordered-list'
- import ListItem from '@tiptap/extension-list-item'
- import ListKeymap from '@tiptap/extension-list-keymap'
- import TaskList from '@tiptap/extension-task-list'
- import TaskItem from '@tiptap/extension-task-item'
+ import { BulletList, OrderedList, ListItem, ListKeymap, TaskList, TaskItem } from '@tiptap/extension-list'

Extensions
- import Focus from '@tiptap/extension-focus'
- import Placeholder from '@tiptap/extension-placeholder'
- import History from '@tiptap/extension-history'
- import Dropcursor from '@tiptap/extension-dropcursor'
- import Gapcursor from '@tiptap/extension-gapcursor'
- import CharacterCount from '@tiptap/extension-character-count'
+ import { Focus, Placeholder, UndoRedo, Dropcursor, Gapcursor, CharacterCount } from '@tiptap/extensions'

CollaborationCursor
- import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
+ import CollaborationCaret from '@tiptap/extension-collaboration-caret'

Collaboration History
- import CollaborationHistory from '@tiptap-pro/extension-collaboration-history'
+ import Snapshot from '@tiptap-pro/extension-snapshot'

React Menus
- import { BubbleMenu, FloatingMenu } from '@tiptap/react'
+ import { BubbleMenu, FloatingMenu } from '@tiptap/react/menus'

Vue 3 Menus
- import { BubbleMenu, FloatingMenu } from '@tiptap/vue-3'
+ import { BubbleMenu, FloatingMenu } from '@tiptap/vue-3/menus'

Vue 2 Menus
- import { BubbleMenu, FloatingMenu } from '@tiptap/vue-2'
+ import { BubbleMenu, FloatingMenu } from '@tiptap/vue-2/menus'
```

### Menu Systems

Tippy.js has been replaced with Floating UI for all floating elements. This affects:

- @tiptap/extension-bubble-menu
- @tiptap/extension-drag-handle
- @tiptap/extension-drag-handle-react
- @tiptap/extension-drag-handle-vue-2
- @tiptap/extension-drag-handle-vue-3
- @tiptap/extension-floating-menu
- @tiptap/extension-mention
- @tiptap/suggestion
- @tiptap-pro/extension-emoji

Example migration:

```tsx
// Before
import { BubbleMenu } from '@tiptap/react'

const menu = <BubbleMenu tippyOptions={{ duration: 100 }}>{/* menu content */}</BubbleMenu>

// After
import { BubbleMenu } from '@tiptap/react/menus'
import { offset } from '@floating-ui/dom'
const menu = (
  <BubbleMenu
    options={{
      offset: 6,
      placement: 'top',
    }}
  >
    {/* menu content */}
  </BubbleMenu>
)
```

- New required dependency: `@floating-ui/dom`. Install it with:

```bash
npm install @floating-ui/dom@^1.6.0
```

Make sure to uninstall `tippy.js` if you were using it, as it is no longer needed.

```bash
npm uninstall tippy.js
```

### API Changes Text Style Updates

- `mergeNestedSpanStyles` now defaults to `true`
- New text style extensions added:
  - `font-size`
  - `background-color`
  - `line-height`
- `TextStyleKit` API available for configuring multiple extensions

You can now use the new `TextStyleKit` for easier configuration:

```ts
import { TextStyleKit } from '@tiptap/extension-text-style'

new Editor({
  extensions: [
    TextStyleKit.configure({
      backgroundColor: {
        types: ['textStyle'],
      },
      color: {
        types: ['textStyle'],
      },
      fontFamily: {
        types: ['textStyle'],
      },
      fontSize: {
        types: ['textStyle'],
      },
      lineHeight: {
        types: ['textStyle'],
      },
    }),
  ],
})
```

### Introducing `shouldRerenderOnTransaction`

The `@tiptap/react` Editor configuration now includes `shouldRerenderOnTransaction`, controlling component rerendering.

Previously (pre-3.0.0), the Editor rerendered on every transaction-induced state update, facilitating continuous editor object tracking but potentially impacting rendering performance.

`shouldRerenderOnTransaction` is disabled by default. Enable it by setting `shouldRerenderOnTransaction: true` in the editor configuration.

Post-upgrade, UI elements relying on the Editor's state might become unresponsive. Solutions include disabling the option (potential performance implications) or implementing manual state tracking, as demonstrated:

```js
function MyEditor() {
  const [selection, setSelection] = useState({ from: 0, to: 0 });

  const editor = useEditor({
    // Editor configuration
    onTransaction({ transaction }) {
      setSelection({
        from: transaction.selection.from,
        to: transaction.selection.to,
      });
    },
  });
}
```

You can also use `useEditorState` to extract either the whole state or select specific values to extract.

```js
const { currentSelection } = useEditorState({
  editor,
  selector: (snapshot) => {
    return { currentSelection: snapshot.editor.state.selection }
  },
})
```

This allows explicit state extraction and management for dependent UI logic.

### Command Changes

- `clearContent` and `setContent` now emit updates by default
- `setContent` signature changed to (content, options)
- `insertContent` behavior modified to prevent splitting text nodes at the beginning

### NodeView Changes

The `getPos` function in NodeViewRendererProps can now return `undefined`. Update your code to handle this case:

```ts
// Before
const pos = nodeViewProps.getPos()

// After
const pos = nodeViewProps.getPos()
if (pos !== undefined) {
  // use pos
}
```

### Removed Features

- `editor.getCharacterCount()` method has been removed
- `considerAnyAsEmpty` option removed from placeholder extension

## New Features

### Extensions Package

The new `@tiptap/extensions` package combines multiple utility extensions:

- [CharacterCount](https://tiptap.dev/docs/editor/extensions/functionality/character-count.md)
- [Dropcursor](https://tiptap.dev/docs/editor/extensions/functionality/dropcursor.md)
- [Gapcursor](https://tiptap.dev/docs/editor/extensions/functionality/gapcursor.md)
- [History](https://tiptap.dev/docs/editor/extensions/functionality/undo-redo.md) (now named `UndoRedo`)
- [Placeholder](https://tiptap.dev/docs/editor/extensions/functionality/placeholder.md)
- [TrailingNode](https://tiptap.dev/docs/editor/extensions/functionality/trailing-node.md)
- [Focus](https://tiptap.dev/docs/editor/extensions/functionality/focus.md)
- [Selection](https://tiptap.dev/docs/editor/extensions/functionality/selection.md)

This will automatically update the imports in your project.

Example migration:

```diff
- import CharacterCount from '@tiptap/extension-character-count'
+ import { CharacterCount } from '@tiptap/extensions'
```

### Server-Side Rendering

Improved SSR support with the ability to run the editor on the server-side without rendering:

```ts
const editor = new Editor({
  element: null, // opt-in to SSR
  content: {
    type: 'doc',
    content: [
      /* ... */
    ],
  },
  extensions: [
    /* ... */
  ],
})
```

### Mark Views

Adds support for [mark views](https://prosemirror.net/docs/ref/#view.MarkView), which allow you to render custom views for marks within the editor. This is useful for rendering custom UI for marks, like a color picker for a text color mark or a link editor for a link mark.

Including support for React and Vue 3 frameworks

```ts
// Plain JS
import { Mark } from '@tiptap/core'

Mark.create({
  // Other options...
  addMarkView() {
    return ({ mark, HTMLAttributes }) => {
      const dom = document.createElement('b')
      const contentDOM = document.createElement('span')

      dom.appendChild(contentDOM)

      return {
        dom,
        contentDOM,
      }
    }
  },
})

// React
import { Mark } from '@tiptap/core'
import { ReactMarkViewRenderer } from '@tiptap/react'

Mark.create({
  // ... other options
  addMarkView() {
    return ReactMarkViewRenderer(YourComponent)
  },
})

// Vue 3
import { Mark } from '@tiptap/core'
import { VueMarkViewRenderer } from '@tiptap/vue-3'

Mark.create({
  addMarkView() {
    return VueMarkViewRenderer(Component)
  },
})
```

### Other Improvements

- New delete event tracking
- HTML parsing now uses happy-dom-without-node
- New node/mark attribute validation support
- Performance improvements for transaction handling

## StarterKit Updates

StarterKit now includes these extensions by default:

- [Link](https://tiptap.dev/docs/editor/extensions/marks/link.md)
- [ListKeymap](https://tiptap.dev/docs/editor/extensions/functionality/listkeymap.md)
- [Underline](https://tiptap.dev/docs/editor/extensions/marks/underline.md)

If you've installed these separately, you can remove them:

```diff
- import Link from '@tiptap/extension-link'
- import ListKeymap from '@tiptap/extension-list-keymap'
- import Underline from '@tiptap/extension-underline'
```

Also make sure to update disabled extension names in your StarterKit configuration if you were using them:

```diff
const editor = new Editor({
  extensions: [
    StarterKit.configure({
-      history: false, // disable history
+      undoRedo: false // disable undo/redo (previously history)
    })
  ]
})
```

## Migration Steps

1. Update Dependencies

   - Remove UMD-dependent code
   - Install `@floating-ui/dom` (for bubble & floating menus)
   - Update Tiptap packages to v3

2. Update Menu Implementations

   - Replace `tippyOptions` with Floating UI options
   - Update menu imports to use `/menus` suffix

3. Review NodeView Usage

   - Add checks for `undefined` `getPos`

4. Update Extensions

   - Migrate to `@tiptap/extensions` where applicable
   - Remove redundant `StarterKit` extensions
   - Update text style configurations

5. Review Command Usage

   - Update `setContent` calls to use new signature
   - Check `clearContent` behavior with default updates
