Skip to main content

Overview

The useEditor composable is the primary way to create and manage a Tiptap editor instance in Vue 3 applications. It automatically handles the editor lifecycle, creating the editor on component mount and destroying it on unmount.

Signature

function useEditor(
  options?: Partial<EditorOptions>
): Ref<Editor | undefined>

Parameters

options
Partial<EditorOptions>
default:"{}"
Configuration options for the editor. Accepts all standard EditorOptions from @tiptap/core.Common options include:
  • content - Initial content for the editor
  • extensions - Array of Tiptap extensions to use
  • editable - Whether the editor is editable
  • autofocus - Auto-focus behavior
  • editorProps - ProseMirror editor props
  • onUpdate - Callback fired when content changes
  • onCreate - Callback fired when editor is created
  • onDestroy - Callback fired when editor is destroyed

Return Value

Returns a shallow ref containing the Editor instance. The ref will be undefined until the component is mounted, at which point it will contain the initialized editor. Type: Ref<Editor | undefined>

Lifecycle

  • onMounted: Creates the editor instance with the provided options
  • onBeforeUnmount: Clones the editor’s DOM node to preserve content, then destroys the editor instance

Examples

Basic Usage

<script setup>
import { useEditor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'

const editor = useEditor({
  content: '<p>Hello World!</p>',
  extensions: [
    StarterKit,
  ],
})
</script>

<template>
  <EditorContent :editor="editor" />
</template>

With Event Handlers

<script setup>
import { useEditor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
import { ref } from 'vue'

const content = ref('')

const editor = useEditor({
  content: '<p>Edit me!</p>',
  extensions: [
    StarterKit,
  ],
  onUpdate: ({ editor }) => {
    content.value = editor.getHTML()
  },
  onCreate: ({ editor }) => {
    console.log('Editor created:', editor)
  },
})
</script>

<template>
  <div>
    <EditorContent :editor="editor" />
    <div>{{ content }}</div>
  </div>
</template>

With Editable Control

<script setup>
import { useEditor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
import { ref, watch } from 'vue'

const isEditable = ref(true)

const editor = useEditor({
  content: '<p>Toggle edit mode</p>',
  extensions: [
    StarterKit,
  ],
  editable: isEditable.value,
})

watch(isEditable, (newValue) => {
  editor.value?.setEditable(newValue)
})
</script>

<template>
  <div>
    <button @click="isEditable = !isEditable">
      {{ isEditable ? 'Disable' : 'Enable' }} Editing
    </button>
    <EditorContent :editor="editor" />
  </div>
</template>

Accessing Editor Methods

<script setup>
import { useEditor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'

const editor = useEditor({
  content: '<p>Use editor commands</p>',
  extensions: [
    StarterKit,
  ],
})

function toggleBold() {
  editor.value?.chain().focus().toggleBold().run()
}

function getHTML() {
  return editor.value?.getHTML()
}
</script>

<template>
  <div>
    <button @click="toggleBold">Bold</button>
    <EditorContent :editor="editor" />
  </div>
</template>

Notes

  • The editor ref uses Vue’s shallowRef for optimal performance
  • The editor is automatically destroyed when the component unmounts, with DOM content preservation
  • Always check if editor.value exists before calling methods, as it’s undefined before mount
  • The returned ref is reactive and can be watched or used in computed properties

See Also

Build docs developers (and LLMs) love