A headless, framework-agnostic rich text editor for modern web applications, built on top of ProseMirror.
pnpm add @tiptap/react @tiptap/pm @tiptap/starter-kit
import { useEditor, EditorContent } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; function TextEditor() { const editor = useEditor({ extensions: [ StarterKit, ], content: '<p>Hello World! 🌎️</p>', }); return ( <div className="editor-container"> <div className="menu"> <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: 1 }).run()} className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''} > H1 </button> </div> <EditorContent editor={editor} /> </div> ); }
import { useEditor, EditorContent } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import Placeholder from '@tiptap/extension-placeholder'; import Image from '@tiptap/extension-image'; import Link from '@tiptap/extension-link'; function AdvancedEditor() { const editor = useEditor({ extensions: [ StarterKit, Placeholder.configure({ placeholder: 'Write something amazing...', }), Image, Link.configure({ openOnClick: false, }), ], content: '<p>This is an advanced editor with image and link support.</p>', }); // Function to add an image const addImage = () => { const url = window.prompt('URL'); if (url) { editor.chain().focus().setImage({ src: url }).run(); } }; // Function to add a link const setLink = () => { const url = window.prompt('URL'); if (url) { editor.chain().focus().setLink({ href: url }).run(); } }; return ( <div className="editor-container"> <div className="menu"> {/* Basic formatting buttons */} <button onClick={addImage}>Image</button> <button onClick={setLink}>Link</button> </div> <EditorContent editor={editor} /> </div> ); }