Documentation Index Fetch the complete documentation index at: https://mintlify.com/ueberdosis/tiptap/llms.txt
Use this file to discover all available pages before exploring further.
Quickstart
Get up and running with Tiptap in just a few minutes. This guide will walk you through creating a basic editor with common formatting options.
Basic Setup
Let’s create a simple editor with the starter kit. Choose your framework below:
Create the Editor Here’s a minimal React example using Tiptap: import { useEditor , EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
export default function Editor () {
const editor = useEditor ({
extensions: [ StarterKit ],
content: '<p>Hello World! 🌎</p>' ,
})
return < EditorContent editor = { editor } />
}
What’s Happening?
Import the necessary packages
useEditor - A React hook to create and manage the editor instance
EditorContent - A React component that renders the editor
StarterKit - A bundle of essential extensions
Initialize the editor with useEditor
The useEditor hook takes a configuration object with:
extensions - Array of extensions to enable
content - Initial HTML content for the editor
Render the editor
The EditorContent component takes the editor instance and renders the editing interface
Here’s a more complete example with a formatting toolbar (from demos/src/Examples/Default/React/index.tsx): import { TextStyleKit } from '@tiptap/extension-text-style'
import { EditorContent , useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import React from 'react'
const extensions = [ TextStyleKit , StarterKit ]
export default function Editor () {
const editor = useEditor ({
extensions ,
content: `
<h2>Hi there,</h2>
<p>
This is a <em>basic</em> example of <strong>Tiptap</strong>.
Sure, there are all kinds of basic text styles you'd probably
expect from a text editor. But wait until you see the lists:
</p>
<ul>
<li>That's a bullet list with one …</li>
<li>… or two list items.</li>
</ul>
<p>
Isn't that great? And all of that is editable. But wait,
there's more. Let's try a code block:
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<blockquote>
Wow, that's amazing. Good work! 👏
</blockquote>
` ,
})
if ( ! editor ) {
return null
}
return (
< div >
< div className = "toolbar" >
< button
onClick = { () => editor . chain (). focus (). toggleBold (). run () }
className = { editor . isActive ( 'bold' ) ? 'is-active' : '' }
>
Bold
</ button >
< button
onClick = { () => editor . chain (). focus (). toggleItalic (). run () }
className = { editor . isActive ( 'italic' ) ? 'is-active' : '' }
>
Italic
</ button >
< button
onClick = { () => editor . chain (). focus (). toggleHeading ({ level: 2 }). run () }
className = { editor . isActive ( 'heading' , { level: 2 }) ? 'is-active' : '' }
>
H2
</ button >
< button
onClick = { () => editor . chain (). focus (). toggleBulletList (). run () }
className = { editor . isActive ( 'bulletList' ) ? 'is-active' : '' }
>
Bullet List
</ button >
</ div >
< EditorContent editor = { editor } />
</ div >
)
}
Cleanup Always destroy the editor when the component unmounts to prevent memory leaks. The useEditor hook handles this automatically. Create the Editor Here’s a minimal Vue 3 example (from demos/src/Overview/Installation/Vue/index.vue): < template >
< editor-content : editor = " editor " />
</ template >
< script >
import StarterKit from '@tiptap/starter-kit'
import { Editor , EditorContent } from '@tiptap/vue-3'
export default {
components: {
EditorContent ,
} ,
data () {
return {
editor: null ,
}
} ,
mounted () {
this . editor = new Editor ({
content: '<p>Hello World! 🌎</p>' ,
extensions: [ StarterKit ],
})
} ,
beforeUnmount () {
this . editor . destroy ()
} ,
}
</ script >
What’s Happening?
Import the packages
Editor - The core editor class
EditorContent - Vue component that renders the editor
StarterKit - Essential extensions bundle
Register the component
Register EditorContent in your component’s components option
Initialize in mounted()
Create the editor instance in the mounted lifecycle hook
Clean up in beforeUnmount()
Always destroy the editor to prevent memory leaks
Complete Example with Composition API < template >
< div >
< div class = "toolbar" v-if = " editor " >
< button
@ click = " editor . chain (). focus (). toggleBold (). run () "
: class = " { 'is-active' : editor . isActive ( 'bold' ) } "
>
Bold
</ button >
< button
@ click = " editor . chain (). focus (). toggleItalic (). run () "
: class = " { 'is-active' : editor . isActive ( 'italic' ) } "
>
Italic
</ button >
< button
@ click = " editor . chain (). focus (). toggleHeading ({ level: 2 }). run () "
: class = " { 'is-active' : editor . isActive ( 'heading' , { level: 2 }) } "
>
H2
</ button >
</ div >
< editor-content : editor = " editor " />
</ div >
</ template >
< 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 >
Create the Editor Here’s how to use Tiptap with vanilla JavaScript: import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
const editor = new Editor ({
element: document . querySelector ( '.editor' ),
extensions: [ StarterKit ],
content: '<p>Hello World! 🌎</p>' ,
})
What’s Happening?
Import the packages
Import Editor from @tiptap/core and the extensions you need
Create the editor instance
Pass a configuration object with:
element - DOM element to mount the editor
extensions - Array of extensions
content - Initial HTML content
The editor is ready
You can now interact with the editor using its API
<! DOCTYPE html >
< html >
< head >
< style >
.toolbar button .is-active {
background : #333 ;
color : white ;
}
.tiptap {
padding : 1 rem ;
border : 1 px solid #ccc ;
min-height : 200 px ;
}
</ style >
</ head >
< body >
< div class = "toolbar" >
< button id = "bold" > Bold </ button >
< button id = "italic" > Italic </ button >
< button id = "heading" > H2 </ button >
</ div >
< div class = "editor" ></ div >
< script type = "module" >
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
const editor = new Editor ({
element: document . querySelector ( '.editor' ),
extensions: [ StarterKit ],
content: '<p>Hello World! 🌎</p>' ,
})
// Add toolbar functionality
document . getElementById ( 'bold' ). addEventListener ( 'click' , () => {
editor . chain (). focus (). toggleBold (). run ()
})
document . getElementById ( 'italic' ). addEventListener ( 'click' , () => {
editor . chain (). focus (). toggleItalic (). run ()
})
document . getElementById ( 'heading' ). addEventListener ( 'click' , () => {
editor . chain (). focus (). toggleHeading ({ level: 2 }). run ()
})
// Update button states
editor . on ( 'transaction' , () => {
document . getElementById ( 'bold' ). classList . toggle (
'is-active' ,
editor . isActive ( 'bold' )
)
document . getElementById ( 'italic' ). classList . toggle (
'is-active' ,
editor . isActive ( 'italic' )
)
document . getElementById ( 'heading' ). classList . toggle (
'is-active' ,
editor . isActive ( 'heading' , { level: 2 })
)
})
</ script >
</ body >
</ html >
Understanding Commands
Tiptap uses a chainable command API to modify the editor content:
// Chain multiple commands together
editor
. chain () // Start a command chain
. focus () // Focus the editor
. toggleBold () // Toggle bold formatting
. run () // Execute the chain
Common Commands
Command Description toggleBold()Toggle bold formatting toggleItalic()Toggle italic formatting toggleStrike()Toggle strikethrough toggleCode()Toggle inline code toggleHeading({ level })Toggle heading (1-6) toggleBulletList()Toggle bullet list toggleOrderedList()Toggle ordered list toggleCodeBlock()Toggle code block toggleBlockquote()Toggle blockquote setHardBreak()Insert line break undo()Undo last change redo()Redo last undone change
Checking Active States
Use isActive() to check if a formatting option is currently active:
editor . isActive ( 'bold' ) // true or false
editor . isActive ( 'heading' , { level: 2 }) // Check heading level
editor . isActive ( 'link' , { href: 'https://...' }) // Check link href
Getting and Setting Content
Get Content
// Get HTML
const html = editor . getHTML ()
// Get JSON
const json = editor . getJSON ()
// Get plain text
const text = editor . getText ()
Set Content
// Set HTML content
editor . commands . setContent ( '<p>New content</p>' )
// Set JSON content
editor . commands . setContent ({
type: 'doc' ,
content: [{
type: 'paragraph' ,
content: [{ type: 'text' , text: 'New content' }]
}]
})
Styling the Editor
Tiptap doesn’t include default styles. Add your own CSS to style the editor:
/* Basic editor styles */
.tiptap {
padding : 1 rem ;
border : 1 px solid #ccc ;
border-radius : 4 px ;
min-height : 200 px ;
}
.tiptap:focus {
outline : none ;
border-color : #0066ff ;
}
/* Heading styles */
.tiptap h1 { font-size : 2 em ; }
.tiptap h2 { font-size : 1.5 em ; }
.tiptap h3 { font-size : 1.25 em ; }
/* List styles */
.tiptap ul ,
.tiptap ol {
padding-left : 1.5 rem ;
margin : 1 rem 0 ;
}
/* Code block styles */
.tiptap pre {
background : #1e1e1e ;
color : #fff ;
padding : 1 rem ;
border-radius : 4 px ;
overflow-x : auto ;
}
.tiptap code {
background : #f0f0f0 ;
padding : 0.2 em 0.4 em ;
border-radius : 3 px ;
font-size : 0.9 em ;
}
/* Blockquote styles */
.tiptap blockquote {
border-left : 3 px solid #ccc ;
padding-left : 1 rem ;
margin : 1 rem 0 ;
font-style : italic ;
}
Next Steps
Now that you have a working editor, explore more features:
Add More Extensions Browse and add more extensions like images, tables, and mentions
Create Custom Extensions Learn how to build your own custom extensions
Add Collaboration Enable real-time collaborative editing with Yjs
Explore Examples See Tiptap in action with interactive examples