Overview
The useEditor hook is the primary way to create and manage a Tiptap editor instance in React applications. It handles the editor lifecycle, including creation, updates, and cleanup.
Type Signature
function useEditor (
options : UseEditorOptions ,
deps ?: DependencyList
) : Editor | null
Parameters
Configuration options for the editor instance. Extends Partial<EditorOptions> from @tiptap/core. Array of Tiptap extensions to use in the editor.
Initial content for the editor. Can be HTML, JSON, or a ProseMirror document.
Whether the editor should be editable.
autofocus
boolean | 'start' | 'end' | number
default: "false"
Automatically focus the editor on mount. Can be true, false, 'start', 'end', or a specific position.
Whether to render the editor on the first render. Set to false for server-side rendering to avoid hydration mismatches.
shouldRerenderOnTransaction
Whether to re-render the editor on each transaction. This is legacy behavior that will be removed in future versions.
onCreate
(props: EditorEvents['create']) => void
Callback function called when the editor is created.
onUpdate
(props: EditorEvents['update']) => void
Callback function called when the editor content changes.
onTransaction
(props: EditorEvents['transaction']) => void
Callback function called on every transaction.
onFocus
(props: EditorEvents['focus']) => void
Callback function called when the editor receives focus.
onBlur
(props: EditorEvents['blur']) => void
Callback function called when the editor loses focus.
onSelectionUpdate
(props: EditorEvents['selectionUpdate']) => void
Callback function called when the selection changes.
onBeforeCreate
(props: EditorEvents['beforeCreate']) => void
Callback function called before the editor is created.
Callback function called when the editor is destroyed.
onContentError
(props: EditorEvents['contentError']) => void
Callback function called when there’s an error with the content.
onDrop
(props: EditorEvents['drop']) => void
Callback function called when content is dropped into the editor.
onPaste
(props: EditorEvents['paste']) => void
Callback function called when content is pasted into the editor.
onDelete
(props: EditorEvents['delete']) => void
Callback function called when content is deleted.
deps
DependencyList
default: "[]"
Optional React dependency array. When dependencies change, the editor instance will be destroyed and recreated.
Return Value
Returns an Editor instance or null. The return value can be null when:
The editor has not been initialized yet
immediatelyRender is set to false and the editor hasn’t mounted
Server-side rendering is detected
Usage Examples
Basic Usage
import { useEditor , EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
function MyEditor () {
const editor = useEditor ({
extensions: [ StarterKit ],
content: '<p>Hello World!</p>' ,
})
return < EditorContent editor = { editor } />
}
With Event Handlers
import { useEditor , EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { useState } from 'react'
function MyEditor () {
const [ status , setStatus ] = useState ( 'initializing' )
const editor = useEditor ({
extensions: [ StarterKit ],
content: '<p>Hello World!</p>' ,
onCreate : () => {
setStatus ( 'created' )
},
onUpdate : ({ editor }) => {
console . log ( 'Content updated:' , editor . getHTML ())
},
onFocus : () => {
setStatus ( 'focused' )
},
onBlur : () => {
setStatus ( 'blurred' )
},
})
return (
< div >
< p > Editor status: { status } </ p >
< EditorContent editor = { editor } />
</ div >
)
}
With Dependencies
import { useEditor , EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
function MyEditor ({ initialContent } : { initialContent : string }) {
const editor = useEditor ({
extensions: [ StarterKit ],
content: initialContent ,
}, [ initialContent ]) // Recreate editor when initialContent changes
return < EditorContent editor = { editor } />
}
Server-Side Rendering
import { useEditor , EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
function MyEditor () {
const editor = useEditor ({
extensions: [ StarterKit ],
content: '<p>Hello World!</p>' ,
immediatelyRender: false , // Required for SSR
})
if ( ! editor ) {
return < div > Loading editor... </ div >
}
return < EditorContent editor = { editor } />
}
Controlled Editor
import { useEditor , EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { useEffect , useState } from 'react'
function MyEditor () {
const [ content , setContent ] = useState ( '<p>Hello World!</p>' )
const editor = useEditor ({
extensions: [ StarterKit ],
content ,
onUpdate : ({ editor }) => {
setContent ( editor . getHTML ())
},
})
// Update editor when external content changes
useEffect (() => {
if ( editor && editor . getHTML () !== content ) {
editor . commands . setContent ( content )
}
}, [ content , editor ])
return (
< div >
< EditorContent editor = { editor } />
< textarea
value = { content }
onChange = { ( e ) => setContent ( e . target . value ) }
/>
</ div >
)
}
Important Notes
When using server-side rendering (SSR) with frameworks like Next.js, you must set immediatelyRender: false to avoid hydration mismatches. In development mode, Tiptap will throw an error if SSR is detected without this option.
The shouldRerenderOnTransaction option is legacy behavior. For better performance, leave it as false (default) and use the useEditorState hook for reactive state updates instead.
Use the deps array sparingly. Only include dependencies when you actually need to recreate the editor instance. For most use cases, updating editor options or content through commands is more efficient.