Nuxt

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

Requirements

  • Node installed on your machine
  • Experience with Vue

Create a project (optional)

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

For the purpose of this guide, start with a fresh Nuxt project called my-tiptap-project. The following command sets up everything you need:

# create a project
npx nuxi@latest init my-tiptap-project

# change directory
cd my-tiptap-project

Install the dependencies

Now 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:3000/ 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.

Since Nuxt uses server-side rendering (SSR), we set immediatelyRender: false to prevent the editor from rendering on the server. The editor requires browser APIs that aren't available during SSR, so this option ensures it only renders on the client after hydration.

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

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

  const editor = useEditor({
    content: `<p>I'm running Tiptap with Vue.js. 🎉</p>`,
    extensions: [StarterKit],
    // Don't render on the server, only on the client after hydration
    immediatelyRender: false,
  })
</script>

Add it to your app

Now, replace the content of app/app.vue with the following code to use our new TiptapEditor component:

<template>
  <TiptapEditor />
</template>

In Nuxt 4, both components and Vue composables (like ref and watch) are auto-imported, so you don't need to manually import or register them.

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>
  <EditorContent :editor="editor" />
</template>

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

  const emit = defineEmits(['update:modelValue'])
  const props = defineProps({
    modelValue: {
      type: String,
      default: '',
    },
  })

  const editor = useEditor({
    content: props.modelValue,
    extensions: [StarterKit],
    // Don't render on the server, only on the client after hydration
    immediatelyRender: false,
    onUpdate: ({ editor }) => {
      // HTML
      emit('update:modelValue', editor.getHTML())

      // JSON
      // emit('update:modelValue', editor.getJSON())
    },
  })

  watch(
    () => props.modelValue,
    (value) => {
      // HTML
      const isSame = editor.value?.getHTML() === value

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

      if (isSame) {
        return
      }

      editor.value?.commands.setContent(value, false)
    }
  )
</script>

Next steps