Nuxt

This guide covers how to integrate Tiptap with your Nuxt.js project, complete with code examples.

Requirements

  • Node installed on your machine
  • Experience with Vue

Create a project (optional)

If you already have a Nuxt.js project, that's fine too. Just skip this step.

For the purpose of this project, start with a fresh Nuxt.js project called my-tiptap-project. The following command sets up everything we need. It asks a lot of questions, but just use what floats your boat or use the defaults.

# create a project
npm init nuxt-app my-tiptap-project

# change directory
cd my-tiptap-project

Install the dependencies

Enough of the boring boilerplate work. Let's install Tiptap! For the following example, you'll need the @tiptap/vue-3 package with a few components, the @tiptap/pm package, and @tiptap/starter-kit, which has the most common extensions to get started quickly.

npm install @tiptap/vue-3 @tiptap/pm @tiptap/starter-kit

If you followed steps 1 and 2, you can now start your project with npm run dev and open http://localhost:8080/ in your favorite browser. This might be different if you're working with an existing project.

Integrate Tiptap

To actually start using Tiptap, you'll need to add a new component to your app. Let's call it TiptapEditor and put the following example code in components/TiptapEditor.vue.

This is the fastest way to get Tiptap up and running with Vue. It will give you a very basic version of Tiptap, without any buttons. No worries, you will be able to add more functionality soon.

<template>
  <editor-content :editor="editor" />
</template>

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

  export default {
    components: {
      EditorContent,
    },

    data() {
      return {
        editor: null,
      }
    },

    mounted() {
      this.editor = new Editor({
        content: '<p>I'm running Tiptap with Vue.js. 🎉</p>',
        extensions: [StarterKit],
      })
    },

    beforeUnmount() {
      this.editor.destroy()
    },
  }
</script>

Add it to your app

Now, let's replace the content of pages/index.vue with the following example code to use our new TiptapEditor component in our app.

<template>
  <div>
    <client-only>
      <tiptap-editor />
    </client-only>
  </div>
</template>
<script>
  import TiptapEditor from '~/components/TiptapEditor.vue'
  export default {
    components: {
      TiptapEditor,
    },
  }
</script>

Note that Tiptap needs to run in the client, not on the server. It's required to wrap the editor in a <client-only> tag. Read more about client-only components.

You should now see Tiptap in your browser. Time to give yourself a pat on the back! :)

Use v-model (optional)

You're probably used to binding your data with v-model in forms. This also possible with Tiptap. Here's a working example component, that you can integrate in your project:

<template>
  <editor-content :editor="editor" />
</template>

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

  export default {
    components: {
      EditorContent,
    },

    props: {
      value: {
        type: String,
        default: '',
      },
    },

    data() {
      return {
        editor: null,
      }
    },

    watch: {
      value(value) {
        // HTML
        const isSame = this.editor.getHTML() === value

        // JSON
        // const isSame = JSON.stringify(this.editor.getJSON()) === JSON.stringify(value)

        if (isSame) {
          return
        }

        this.editor.commands.setContent(value, false)
      },
    },

    mounted() {
      this.editor = new Editor({
        content: this.value,
        extensions: [StarterKit],
        onUpdate: () => {
          // HTML
          this.$emit('input', this.editor.getHTML())

          // JSON
          // this.$emit('input', this.editor.getJSON())
        },
      })
    },

    beforeUnmount() {
      this.editor.destroy()
    },
  }
</script>