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

# Migrate from Slate to Tiptap

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

Tiptap is a popular Slate alternative and migrating from Slate to Tiptap is straightforward. This guide will help you transition from Slate's JSON structure to Tiptap's extension system.

## Content migration

### HTML content compatibility

Slate uses a custom JSON structure that needs to be converted for Tiptap. You'll need to serialize your Slate content to HTML first:

```ts
// Convert Slate JSON to HTML using Slate's serialization
import { serialize } from 'slate-html-serializer'

const rules = [
  {
    serialize(obj, children) {
      if (obj.object === 'block') {
        switch (obj.type) {
          case 'paragraph':
            return <p>{children}</p>
          case 'heading-one':
            return <h1>{children}</h1>
          case 'heading-two':
            return <h2>{children}</h2>
          // Add more block types as needed
        }
      }
      if (obj.object === 'mark') {
        switch (obj.type) {
          case 'bold':
            return <strong>{children}</strong>
          case 'italic':
            return <em>{children}</em>
          // Add more mark types as needed
        }
      }
    },
  },
]

const htmlContent = serialize(slateValue, { rules })

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

For simpler Slate structures, you might be able to map directly to Tiptap's JSON format:

```ts
// Example Slate to Tiptap JSON conversion
function slateToTiptap(slateNodes) {
  return {
    type: 'doc',
    content: slateNodes.map((node) => {
      if (node.type === 'paragraph') {
        return {
          type: 'paragraph',
          content: node.children.map((child) => ({
            type: 'text',
            text: child.text,
            marks: child.bold ? [{ type: 'bold' }] : [],
          })),
        }
      }
      // Add more node type mappings
    }),
  }
}

const tiptapContent = slateToTiptap(slateValue.document.nodes)
const editor = new Editor({
  content: tiptapContent,
  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 Slate editor with Tiptap:

```tsx
// Slate (before)
import { createEditor } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'

const [editor] = useState(() => withReact(createEditor()))
const [value, setValue] = useState(initialValue)

return (
  <Slate editor={editor} value={value} onChange={setValue}>
    <Editable />
  </Slate>
)

// 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 Slate's plugin system. Each feature is an independent extension with clear APIs and configuration options.

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 Slate plugin equivalents

| Slate Concept    | Tiptap Extension                        | Notes                  |
| ---------------- | --------------------------------------- | ---------------------- |
| Bold mark        | `Bold`                                  | Included in StarterKit |
| Italic mark      | `Italic`                                | Included in StarterKit |
| Underline mark   | `Underline`                             | Included in StarterKit |
| Link mark        | `Link`                                  | Included in StarterKit |
| Image block      | `Image`                                 | Available separately   |
| List blocks      | `BulletList`, `OrderedList`, `ListItem` | Included in StarterKit |
| Heading blocks   | `Heading`                               | Included in StarterKit |
| Blockquote block | `Blockquote`                            | Included in StarterKit |
| Code block       | `CodeBlock`                             | Included in StarterKit |
| Table blocks     | `Table`                                 | 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'

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

### Custom extensions

For Slate 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

Slate's custom toolbar components translate to Tiptap UI components:

```tsx
// Slate toolbar (before)
const Toolbar = () => {
  const editor = useSlate()

  return (
    <div>
      <Button
        active={isMarkActive(editor, 'bold')}
        onMouseDown={(event) => {
          event.preventDefault()
          toggleMark(editor, 'bold')
        }}
      >
        Bold
      </Button>
    </div>
  )
}

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

  return (
    <div className="toolbar">
      <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={() => editor.chain().focus().toggleUnderline().run()}
        className={editor.isActive('underline') ? 'active' : ''}
      >
        Underline
      </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)

### Hovering toolbar

Replicate Slate's hovering toolbar 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>
    </>
  )
}
```

### Node views (custom elements)

Slate's custom elements can be replaced with Tiptap's Node Views. Learn more about Node Views in our [official guide](https://tiptap.dev/docs/editor/extensions/custom-extensions/node-views.md)

```tsx
// Slate custom element (before)
const ImageElement = ({ attributes, children, element }) => {
  return (
    <div {...attributes}>
      <img src={element.url} />
      {children}
    </div>
  )
}

// Tiptap Node View (after)
import { Node } from '@tiptap/core'
import { ReactNodeViewRenderer } from '@tiptap/react'

const ImageComponent = ({ node }) => {
  return <img src={node.attrs.src} />
}

const CustomImage = Node.create({
  name: 'customImage',

  addNodeView() {
    return ReactNodeViewRenderer(ImageComponent)
  },
})
```

## Migration checklist

Install Tiptap packages
Convert Slate JSON content to HTML or Tiptap JSON
Replace Slate editor initialization with Tiptap setup
Map Slate plugins to Tiptap extensions
Migrate custom elements to [Node Views](https://tiptap.dev/docs/editor/extensions/custom-extensions/node-views.md)
Migrate toolbar components to Tiptap UI
Test content compatibility
Convert existing content to JSON format (recommended)
Implement custom extensions for any missing functionality
Update event handlers and API calls
Test hovering toolbar functionality
Verify custom element rendering

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