Skip to main content
The Editor class is the core of Tiptap. It manages the editor state, handles transactions, and provides methods to interact with your content.

Creating an Editor

The simplest way to create an editor is to instantiate the Editor class:
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>',
})

Editor Options

The Editor constructor accepts a configuration object with the following options:
element
HTMLElement | null
The DOM element where the editor should be mounted. Can be null if you want to mount it later.
content
string | JSONContent
The initial content of the editor. Can be HTML string or JSON.
// HTML content
content: '<p>Hello World!</p>'

// JSON content
content: {
  type: 'doc',
  content: [
    {
      type: 'paragraph',
      content: [{ type: 'text', text: 'Hello World!' }]
    }
  ]
}
extensions
Extension[]
default:"[]"
An array of extensions to use in the editor. Extensions add functionality like nodes, marks, and commands.
editable
boolean
default:"true"
Whether the editor is editable.
autofocus
boolean | 'start' | 'end' | number
default:"false"
Whether the editor should be focused on initialization.
  • true or 'start': Focus at the start
  • 'end': Focus at the end
  • number: Focus at a specific position
injectCSS
boolean
default:"true"
Whether to inject the default Tiptap CSS styles.
enableInputRules
boolean
default:"true"
Whether to enable input rules (e.g., markdown shortcuts).
enablePasteRules
boolean
default:"true"
Whether to enable paste rules.
enableCoreExtensions
boolean
default:"true"
Whether to enable core extensions (required for basic functionality).

Event Handlers

The editor emits events at different stages of its lifecycle:
onCreate
({ editor }) => void
Called when the editor is created and ready.
onCreate: ({ editor }) => {
  console.log('Editor is ready!', editor.getHTML())
}
onUpdate
({ editor, transaction }) => void
Called whenever the document changes.
onUpdate: ({ editor }) => {
  const html = editor.getHTML()
  console.log('Content updated:', html)
}
onSelectionUpdate
({ editor }) => void
Called when the selection changes.
onTransaction
({ editor, transaction }) => void
Called for every transaction (even if the document didn’t change).
onFocus
({ editor, event }) => void
Called when the editor receives focus.
onBlur
({ editor, event }) => void
Called when the editor loses focus.
onDestroy
() => void
Called when the editor is destroyed.

Core Methods

Content Methods

setContent
(content: string | JSONContent, options?: SetContentOptions) => Editor
Replace the entire document with new content.
// Set HTML content
editor.commands.setContent('<p>New content</p>')

// Set JSON content
editor.commands.setContent({
  type: 'doc',
  content: [
    { type: 'paragraph', content: [{ type: 'text', text: 'New content' }] }
  ]
})

// Don't emit update event
editor.commands.setContent('<p>New content</p>', { emitUpdate: false })
Source: /home/daytona/workspace/source/packages/core/src/commands/setContent.ts:35
getHTML
() => string
Get the current document as HTML.
const html = editor.getHTML()
// Returns: '<p>Hello World!</p>'
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:737
getJSON
() => JSONContent
Get the current document as JSON.
const json = editor.getJSON()
// Returns: { type: 'doc', content: [...] }
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:727
getText
(options?: { blockSeparator?: string }) => string
Get the current document as plain text.
const text = editor.getText()
// Returns: 'Hello World!'

// Custom separator between blocks
const text = editor.getText({ blockSeparator: ' ' })
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:744

Focus Methods

focus
(position?: 'start' | 'end' | number | boolean) => Editor
Focus the editor at a specific position.
// Focus at current position
editor.commands.focus()

// Focus at start
editor.commands.focus('start')

// Focus at end
editor.commands.focus('end')

// Focus at specific position
editor.commands.focus(10)
blur
() => Editor
Remove focus from the editor.
editor.commands.blur()

Lifecycle Methods

mount
(element: HTMLElement) => void
Mount the editor to a DOM element.
const editor = new Editor({
  extensions: [StarterKit],
})

// Mount later
const element = document.querySelector('.editor')
editor.mount(element)
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:161
unmount
() => void
Unmount the editor from the DOM (but keep it in memory for later remounting).
editor.unmount()
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:190
destroy
() => void
Destroy the editor and clean up all resources.
editor.destroy()
After calling destroy(), the editor instance cannot be reused. Create a new editor if needed.
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:766

Properties

commands
SingleCommands
Access to all registered commands.
editor.commands.setContent('<p>Hello</p>')
editor.commands.toggleBold()
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:232
schema
Schema
The ProseMirror schema generated from your extensions.
console.log(editor.schema)
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:65
view
EditorView
The ProseMirror editor view.
console.log(editor.view)
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:305
state
EditorState
The current ProseMirror editor state.
console.log(editor.state.selection)
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:353
isFocused
boolean
Whether the editor currently has focus.
if (editor.isFocused) {
  console.log('Editor is focused')
}
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:69
isEditable
boolean
Whether the editor is editable.
if (editor.isEditable) {
  console.log('Editor is editable')
}
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:295
isEmpty
boolean
Whether the editor content is empty.
if (editor.isEmpty) {
  console.log('Editor is empty')
}
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:759
isDestroyed
boolean
Whether the editor has been destroyed.
if (editor.isDestroyed) {
  console.log('Editor is destroyed')
}
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:777
storage
Storage
Access to extension storage.
// Access storage from a specific extension
const count = editor.storage.characterCount.characters()
Source: /home/daytona/workspace/source/packages/core/src/Editor.ts:225

Advanced Usage

Making the Editor Read-only

// Set editable state
editor.setEditable(false)

// Check if editable
if (editor.isEditable) {
  console.log('Editor is editable')
}

Checking Active State

// Check if bold is active
if (editor.isActive('bold')) {
  console.log('Bold is active')
}

// Check if heading level 1 is active
if (editor.isActive('heading', { level: 1 })) {
  console.log('H1 is active')
}

// Check if link with specific href is active
if (editor.isActive('link', { href: 'https://example.com' })) {
  console.log('Link is active')
}

Getting Attributes

// Get attributes of current node/mark
const attrs = editor.getAttributes('link')
console.log(attrs.href)

// Get heading level
const headingAttrs = editor.getAttributes('heading')
console.log(headingAttrs.level) // 1, 2, 3, etc.

Working with Selection

// Get current selection
const { from, to } = editor.state.selection

// Get selected text
const selectedText = editor.state.doc.textBetween(from, to)

// Check if selection is empty
const isEmpty = editor.state.selection.empty

TypeScript Types

import type { Editor, EditorOptions, EditorEvents } from '@tiptap/core'

// Editor options type
const options: Partial<EditorOptions> = {
  content: '<p>Hello</p>',
  editable: true,
}

// Event handler types
type OnUpdate = EditorEvents['update']
// { editor: Editor, transaction: Transaction, appendedTransactions: Transaction[] }

type OnCreate = EditorEvents['create']
// { editor: Editor }

Best Practices

Clean Up Resources

Always call editor.destroy() when you’re done with an editor instance to prevent memory leaks.
useEffect(() => {
  const editor = new Editor({ /* ... */ })
  
  return () => {
    editor.destroy()
  }
}, [])

Batch Updates

Use command chains to batch multiple updates into a single transaction.
// Bad: Multiple transactions
editor.commands.setBold()
editor.commands.setItalic()

// Good: Single transaction
editor.chain().setBold().setItalic().run()

Check Before Acting

Use editor.can() to check if a command can be executed before running it.
if (editor.can().toggleBold()) {
  editor.commands.toggleBold()
}

Commands

Learn about the command system

Extensions

Learn about extensions

Schema

Learn about the ProseMirror schema

Nodes & Marks

Learn about content structure