---
title: "Migrate from CKEditor 5 to Tiptap"
description: "Learn how to migrate your existing CKEditor 5 editor to Tiptap. Complete guide covering content migration, setup, and feature mapping."
canonical_url: "https://tiptap.dev/docs/guides/migrate-from-ckeditor5"
---

# Migrate from CKEditor 5 to Tiptap

Learn how to migrate your existing CKEditor 5 editor to Tiptap. Complete guide covering content migration, setup, and feature mapping.

If you're moving away from CKEditor, Tiptap is a great alternative.Migrating from CKEditor 5 to Tiptap is straightforward. This guide covers everything you need to know for a smooth transition.

## Content migration

### HTML content compatibility

CKEditor 5 typically outputs HTML content, which Tiptap can use directly without any conversion:

```ts
// Your existing CKEditor 5 content
const existingContent =
  '<p>Hello <strong>world</strong>!</p><ul><li>Item 1</li><li>Item 2</li></ul>'

// Use directly in Tiptap
const editor = new Editor({
  content: existingContent,
  extensions: [StarterKit],
})
```

While HTML works perfectly, we recommend converting it to Tiptap's JSON format for better performance and readability. For batch conversion of existing content, use the [HTML utility](https://tiptap.dev/docs/editor/api/utilities/html.md) to convert HTML to JSON programmatically.

## Editor setup

### Installation

First, install Tiptap and its dependencies:

```bash
npm install @tiptap/core @tiptap/starter-kit
```

Tiptap supports all modern frontend UI frameworks like React and Vue. Follow the framework-specific installation instructions in our [installation guides](https://tiptap.dev/docs/editor/getting-started/install.md).

### Basic editor setup

Replace your CKEditor 5 initialization with Tiptap:

```ts
// CKEditor 5 (before)
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'
import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials'
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold'
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic'

ClassicEditor.create(document.querySelector('#editor'), {
  plugins: [Essentials, Bold, Italic],
  toolbar: ['bold', 'italic'],
})

// Tiptap (after)
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'

const editor = new Editor({
  element: document.querySelector('#editor'),
  extensions: [StarterKit],
  content: '<p>Hello World!</p>',
})
```

## Extensions

### Understanding Tiptap's extension system

Tiptap uses a modular extension system that resembles CKEditor 5's plugin architecture. Each feature is an independent extension that can be configured and customized.

The [StarterKit](https://tiptap.dev/docs/editor/extensions/functionality/starterkit.md) is a bundle of all the basic extensions, and you can add or remove other extensions as needed.

Explore all available extensions in our [extensions guide](https://tiptap.dev/docs/editor/extensions/overview.md), or [create your own](https://tiptap.dev/docs/editor/extensions/custom-extensions.md) to support custom functionality and HTML elements.

### Common CKEditor 5 plugin equivalents

| CKEditor 5 Plugin | Tiptap Extension                        | Notes                  |
| ----------------- | --------------------------------------- | ---------------------- |
| `Bold`            | `Bold`                                  | Included in StarterKit |
| `Italic`          | `Italic`                                | Included in StarterKit |
| `List`            | `BulletList`, `OrderedList`, `ListItem` | Included in StarterKit |
| `Link`            | `Link`                                  | Included in StarterKit |
| `Image`           | `Image`                                 | Available separately   |
| `Table`           | `Table`                                 | Available separately   |
| `CodeBlock`       | `CodeBlock`                             | Included in StarterKit |
| `Heading`         | `Heading`                               | Included in StarterKit |
| `Blockquote`      | `Blockquote`                            | Included in StarterKit |
| `Alignment`       | `TextAlign`                             | Available separately   |
| `FontColor`       | `TextStyle`, `Color`                    | Available separately   |
| `FontSize`        | `TextStyle`, `FontSize`                 | Available separately   |

### Extension configuration

```ts
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import Image from '@tiptap/extension-image'
import Table from '@tiptap/extension-table'
import TableRow from '@tiptap/extension-table-row'
import TableHeader from '@tiptap/extension-table-header'
import TableCell from '@tiptap/extension-table-cell'
import TextAlign from '@tiptap/extension-text-align'

const editor = new Editor({
  extensions: [
    StarterKit,
    Image.configure({
      inline: true,
      allowBase64: true,
    }),
    Table.configure({
      resizable: true,
    }),
    TableRow,
    TableHeader,
    TableCell,
    TextAlign.configure({
      types: ['heading', 'paragraph'],
    }),
  ],
})
```

### Custom extensions

For CKEditor 5 custom plugins, create custom Tiptap extensions. See our [custom extensions guide](https://tiptap.dev/docs/editor/extensions/custom-extensions.md) for detailed instructions.

## UI implementation

### Toolbar implementation

CKEditor 5's toolbar configuration translates to custom UI components in Tiptap:

```tsx
// CKEditor 5 toolbar config
toolbar: ['heading', 'bold', 'italic', 'link', 'bulletedList', 'numberedList']

// Tiptap equivalent (React example)
function Toolbar({ editor }) {
  if (!editor) return null

  return (
    <div className="toolbar">
      <select
        onChange={(e) => {
          const level = parseInt(e.target.value)
          if (level === 0) {
            editor.chain().focus().setParagraph().run()
          } else {
            editor.chain().focus().toggleHeading({ level }).run()
          }
        }}
        value={
          editor.isActive('heading', { level: 1 })
            ? 1
            : editor.isActive('heading', { level: 2 })
              ? 2
              : editor.isActive('heading', { level: 3 })
                ? 3
                : 0
        }
      >
        <option value={0}>Paragraph</option>
        <option value={1}>Heading 1</option>
        <option value={2}>Heading 2</option>
        <option value={3}>Heading 3</option>
      </select>

      <button
        onClick={() => editor.chain().focus().toggleBold().run()}
        className={editor.isActive('bold') ? 'active' : ''}
      >
        Bold
      </button>

      <button
        onClick={() => editor.chain().focus().toggleItalic().run()}
        className={editor.isActive('italic') ? 'active' : ''}
      >
        Italic
      </button>

      <button
        onClick={() => {
          const url = window.prompt('URL')
          if (url) {
            editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
          }
        }}
        className={editor.isActive('link') ? 'active' : ''}
      >
        Link
      </button>

      <button
        onClick={() => editor.chain().focus().toggleBulletList().run()}
        className={editor.isActive('bulletList') ? 'active' : ''}
      >
        Bullet List
      </button>

      <button
        onClick={() => editor.chain().focus().toggleOrderedList().run()}
        className={editor.isActive('orderedList') ? 'active' : ''}
      >
        Numbered List
      </button>
    </div>
  )
}
```

### Pre-built UI components

For faster development, use Tiptap's pre-built UI components:

- Explore our [UI components](https://tiptap.dev/docs/ui-components/getting-started/overview.md) for ready-to-use components
- Check out practical examples in our [default text editor example](https://tiptap.dev/docs/examples/basics/default-text-editor.md)

### Balloon editor equivalent

CKEditor 5's balloon editor can be replicated using Tiptap's BubbleMenu:

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

function MyEditor() {
  const editor = useEditor({
    extensions: [StarterKit],
  })

  return (
    <>
      <EditorContent editor={editor} />
      <BubbleMenu editor={editor}>
        <button
          onClick={() => editor.chain().focus().toggleBold().run()}
          className={editor.isActive('bold') ? 'active' : ''}
        >
          Bold
        </button>
        <button
          onClick={() => editor.chain().focus().toggleItalic().run()}
          className={editor.isActive('italic') ? 'active' : ''}
        >
          Italic
        </button>
        <button
          onClick={() => {
            const url = window.prompt('URL')
            if (url) {
              editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
            }
          }}
          className={editor.isActive('link') ? 'active' : ''}
        >
          Link
        </button>
      </BubbleMenu>
    </>
  )
}
```

## Migration checklist

Install Tiptap packages
Replace CKEditor 5 initialization with Tiptap setup
Map CKEditor 5 plugins to Tiptap extensions
Migrate toolbar configuration to custom UI components
Test content compatibility
Convert existing content to JSON format (recommended)
Implement custom extensions for any missing functionality
Update event handlers and API calls
Test balloon/bubble menu functionality if used
Verify image upload and handling
Test table functionality if used

## Next steps

- Explore the [extension overview](https://tiptap.dev/docs/editor/extensions/overview.md) to discover all available extensions
- Learn about [custom extensions](https://tiptap.dev/docs/editor/extensions/custom-extensions.md) for advanced customization
- Check out our [examples](https://tiptap.dev/docs/examples.md) for implementation inspiration
- Review the [performance guide](https://tiptap.dev/docs/guides/performance.md) for optimization tips
