Skip to main content

Overview

The EditorContent component is responsible for rendering the editable area of your Tiptap editor. It connects the editor instance created by useEditor to the DOM and handles the integration with Vue’s component system.

Signature

const EditorContent: DefineComponent<{
  editor: Editor | null
}>

Props

editor
Editor | null
default:"null"
required
The editor instance to render. This should be the ref returned from useEditor.The component will automatically set up the editor’s DOM element and integrate it with Vue’s reactivity system.

Behavior

Mount Phase

When the component mounts or the editor prop changes:
  1. Appends the editor’s ProseMirror view DOM to the component’s root element
  2. Sets up the editor’s app context to enable Vue features like provide/inject
  3. Creates node views for custom Vue-based nodes

Unmount Phase

When the component unmounts:
  1. Cleans up the editor’s content component reference
  2. Removes the app context reference

Rendering

The component renders as a <div> element that contains the ProseMirror editor view. All editor content and interactions happen within this container.

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 Styling

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

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

<template>
  <div class="editor-wrapper">
    <EditorContent :editor="editor" class="editor" />
  </div>
</template>

<style scoped>
.editor-wrapper {
  border: 1px solid #ccc;
  border-radius: 4px;
}

.editor :deep(.ProseMirror) {
  padding: 1rem;
  min-height: 200px;
}

.editor :deep(.ProseMirror:focus) {
  outline: none;
}
</style>

With Conditional Rendering

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

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

<template>
  <div>
    <div v-if="!editor">Loading editor...</div>
    <EditorContent v-else :editor="editor" />
  </div>
</template>

Multiple Editors

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

const editor1 = useEditor({
  content: '<p>Editor 1</p>',
  extensions: [StarterKit],
})

const editor2 = useEditor({
  content: '<p>Editor 2</p>',
  extensions: [StarterKit],
})
</script>

<template>
  <div>
    <div class="editor-container">
      <h3>First Editor</h3>
      <EditorContent :editor="editor1" />
    </div>
    <div class="editor-container">
      <h3>Second Editor</h3>
      <EditorContent :editor="editor2" />
    </div>
  </div>
</template>

With Toolbar

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

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

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

function toggleItalic() {
  editor.value?.chain().focus().toggleItalic().run()
}
</script>

<template>
  <div class="editor-container">
    <div class="toolbar">
      <button @click="toggleBold" :class="{ 'is-active': editor?.isActive('bold') }">
        Bold
      </button>
      <button @click="toggleItalic" :class="{ 'is-active': editor?.isActive('italic') }">
        Italic
      </button>
    </div>
    <EditorContent :editor="editor" />
  </div>
</template>

<style scoped>
.toolbar {
  border-bottom: 1px solid #ccc;
  padding: 0.5rem;
}

.toolbar button {
  margin-right: 0.5rem;
}

.toolbar button.is-active {
  background-color: #000;
  color: #fff;
}
</style>

Notes

  • The component renders a plain <div> that wraps the ProseMirror editor view
  • You can style the editor content using CSS with the :deep() selector to target .ProseMirror
  • The editor prop can be reactive - changing it will update the rendered editor
  • The component automatically handles cleanup when unmounted
  • You can use multiple EditorContent components with different editor instances

See Also