Skip to content

WeTipTap

A rich text editor component that integrates the TipTap editor with Vuetify, providing a user-friendly interface for content creation with formatting options like headings, bold, italic, links, and lists. WeTipTap is a wrapper for tiptap/vue-3, offering simplified configuration and Vuetify integration.

Usage

vue
<template>
  <!-- Basic usage -->
  <WeTipTap v-model="content" label="Description" />
  
  <!-- With character limit -->
  <WeTipTap 
    v-model="content" 
    label="Bio" 
    :limit="500" 
  />
  
  <!-- With validation rules -->
  <WeTipTap
    v-model="content"
    label="Content"
    :rules="[validatorRequired]"
  />
</template>

Props

PropTypeDefaultDescription
modelValueStringundefinedv-model value (HTML content)
labelString''Label text displayed above the editor
rulesArray[]Validation rules (compatible with Vuetify)
errorMessagesArray | String[]Error messages to display
limitNumberundefinedCharacter limit with counter display

Events

EventPayloadDescription
update:modelValueStringEmitted when content changes

Features

  • Rich Text Formatting: Supports bold, italic, headings, links, and lists
  • Toolbar: User-friendly toolbar with formatting buttons
  • Headings: H1-H6 headings available through dropdown menu
  • Lists: Both bullet and numbered lists
  • Links: Insert and edit links
  • Character Count: Optional character counter with limits
  • Validation: Integrates with Vuetify's validation system
  • Undo/Redo: History management for content changes

Editor Extensions

The component comes pre-configured with the following TipTap extensions:

  • StarterKit - Core formatting features
  • Link - URL linking functionality
  • CharacterCount - For tracking character usage

Examples

Basic Rich Text Editor

vue
<script setup>
import { ref } from 'vue'

const description = ref(null)
</script>

<template>
  <v-card>
    <v-card-title>Product Description</v-card-title>
    <v-card-text>
      <WeTipTap
        v-model="description"
        label="Description"
      />
    </v-card-text>
  </v-card>
</template>

With Character Limit and Validation

vue
<script setup>
import { ref } from 'vue'
import { useValidators } from '#imports'

const { validatorRequired } = useValidators()
const bio = ref(null)

const rules = [
  validatorRequired,
  value => !value || value.length >= 100 || 'Bio must be at least 100 characters'
]
</script>

<template>
  <WeTipTap
    v-model="bio"
    label="Author Bio"
    :rules="rules"
    :limit="500"
  />
  
  <div v-if="bio" class="mt-4">
    <h3>Preview:</h3>
    <div v-html="bio"></div>
  </div>
</template>

In a Form Component

vue
<script setup>
import { ref } from 'vue'
import { useForm } from '#imports'

const form = ref(null)
const { model, submit, submitting } = useForm({
  initialValues: {
    title: '',
    content: '',
  },
  form,
  async onSubmit(values) {
    await api.post('articles', values)
  }
})
</script>

<template>
  <v-form ref="form">
    <v-text-field
      v-model="model.title"
      label="Article Title"
      required
    />
    
    <WeTipTap
      v-model="model.content"
      label="Article Content"
    />
    
    <v-btn
      @click="submit"
      :loading="submitting"
      color="primary"
    >
      Publish Article
    </v-btn>
  </v-form>
</template>


<script setup>

const items = [
  { text: 'component', path: 'src/runtime/components/We/TipTap.vue' },
  { text: 'example', path: 'playground/pages/tip-tap.vue' }
]
</script>

## Source Code

<SourceButtons
  :items="items"
/>