Skip to content

Editor ​

Rich text editor component powered by TipTap with configurable formatting toolbar and HTML/Markdown conversion.

Overview ​

VOvEditor provides a lightweight yet powerful rich text editor wrapper around TipTap. It supports multiple formatting options (bold, italic, underline, strike, lists, headings) with a customizable toolbar. The component handles content synchronization via v-model and emits update events.

Features:

  • Multiple formatting options (bold, italic, underline, strike, lists, headings)
  • Configurable toolbar with custom styling
  • v-model support for two-way content binding
  • HTML and Markdown output conversion
  • Full TypeScript support
  • Responsive Material Design icons

Dependencies ​

bash
pnpm add @tiptap/vue-3 @tiptap/pm @tiptap/starter-kit turndown pretty
pnpm i --save-dev @types/turndown @types/pretty
  • @tiptap/vue-3@2: Vue 3 integration for TipTap
  • @tiptap/starter-kit@2: Core TipTap extensions bundle
  • turndown: HTML to Markdown converter
  • pretty: HTML formatter for pretty-printed output

Usage ​

Examples
vue
<template>
  <v-ov-editor
    ref="editor"
    v-model="html"
    @updated="updated"
    :toolbar="[
      'bold',
      'italic',
      'underline',
      'strike',
      'bulletList',
      'orderedList',
      'heading1',
      'heading2',
      'heading3',
    ]"
    toolbar-class="mb-4"
  />
  {{ typing }}
  <h3 class="mt-4">HTML</h3>
  <pre>{{ output.html }}</pre>
  <h3 class="mt-4">Markdown</h3>
  <pre>{{ output.markdown }}</pre>
</template>

<script setup lang="ts">
definePage({
  meta: {
    visibility: 'with-role',
    access: 'with-role',
    roles: ['developer'],
  },
})

const editor = ref()

const html = ref(
  `<h1>What is Lorem Ipsum?</h1>
  <p><strong>Lorem Ipsum</strong>is simply dummy text of the printing and typesetting industry.</p> 
  <p>Lorem Ipsum has been the industry standard dummy text ever since the 1500s.</p>`,
)

const output = computed(() => {
  return {
    html: editor.value?.getHTML(),
    markdown: editor.value?.getMarkdown(),
  }
})

const typing = ref('.')
const updated = () => {
  typing.value = '...'
  setTimeout(() => {
    typing.value = '.'
  }, 500)
}
</script>

API ​

Props ​

PropTypeDefaultDescription
modelValuestring''v-model: The HTML content of the editor
toolbarstring[][]Array of button IDs to display in toolbar
toolbarClassstring''CSS class to apply to toolbar container
editorClassstring''CSS class to apply to editor content area

Events ​

EventPayloadDescription
update:modelValuestringEmitted when content changes (v-model)
updatedstringEmitted when editor content is updated with formatted HTML

Exposed Methods ​

MethodReturnsDescription
getHTML()stringReturns formatted HTML content
getMarkdown()stringReturns Markdown representation of content
editorEditorAccess to underlying TipTap editor instance

Toolbar Buttons ​

Available toolbar button IDs:

IDIconDescription
boldFormatBoldToggle bold formatting
italicFormatItalicToggle italic formatting
underlineFormatUnderlineToggle underline formatting
strikeFormatStrikethroughToggle strikethrough formatting
bulletListFormatListBulletedToggle unordered list
orderedListFormatListNumberedToggle ordered list
heading1FormatHeader1Toggle heading level 1
heading2FormatHeader2Toggle heading level 2
heading3FormatHeader3Toggle heading level 3

Styling ​

The editor uses scoped styles with deep selectors to style the ProseMirror editor instance:

  • .editor-toolbar - Toolbar container (receives toolbarClass prop)
  • .editor-content - Editor content wrapper (receives editorClass prop)

Notes ​

  • The toolbar buttons are automatically filtered based on the toolbar prop - only specified buttons are rendered
  • Active formatting state is reflected in button variant (outlined when active)
  • Content is synchronized in real-time through v-model
  • Editor instance is properly destroyed on component unmount to prevent memory leaks