Back to React & React Native

tiptap

tiptaprich text editorreactwysiwygprosemirrorcontent editorjavascriptfrontend
⭐ 860πŸ“„ MITπŸ•’ 2026-06-11Source β†—

Install this skill

npx skills add jezweb/claude-skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

Tiptap is a headless, extensible rich text framework built on the ProseMirror engine, specifically tailored for modern React applications. Unlike restrictive 'what-you-see-is-what-you-get' editors, Tiptap operates as a core state management library that provides precise control over document content and editor behavior. By utilizing a modular extension system, developers can build everything from simple text inputs to complex collaborative writing environments. It handles the intricate mapping between JSON document structures and HTML output while maintaining stability through well-defined React hooks. When integrated with Tailwind CSS and the standard StarterKit, it offers an efficient path to creating accessible, production-ready editors that avoid common hydration errors in Next.js frameworks. The architecture prioritizes performance and predictable data handling, making it a reliable choice for custom content-authoring tools.

When to Use This Skill

  • β€’Building custom blog or article content management systems
  • β€’Developing collaborative document editing interfaces
  • β€’Creating interactive form inputs with rich formatting requirements
  • β€’Constructing internal dashboards requiring WYSIWYG note-taking

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • β€œSetup a Tiptap rich text editor in my Next.js project
  • β€œHow do I fix Tiptap SSR hydration errors?
  • β€œConfigure image uploads for Tiptap with backend storage
  • β€œAdd Tailwind styling to my Tiptap editor output
  • β€œCreate a custom Tiptap extension for my React app

Pro Tips

  • πŸ’‘Always start with the `StarterKit` to get a foundational set of extensions, then add specific ones like `Image` or `Color` as needed, avoiding unnecessary bloat.
  • πŸ’‘Pay close attention to dependency versions, especially for `ProseMirror` and `Tiptap` itself, to ensure compatibility and leverage the latest features and bug fixes.
  • πŸ’‘When integrating Tiptap into SSR frameworks like Next.js, ensure your editor component is client-side rendered or handled safely to prevent hydration mismatches.

What this skill does

  • β€’Headless content state management via JSON document schema
  • β€’Modular plugin architecture for custom features and extensions
  • β€’Tailwind Typography support for automatic CSS styling
  • β€’SSR compatibility with hydration-safe editor initialization
  • β€’Granular control over image handling, upload patterns, and metadata
  • β€’Advanced text formatting via bundled StarterKit defaults

When not to use it

  • βœ•Simple text areas where formatting is unnecessary or unwanted
  • βœ•Applications requiring high-performance canvas-based drawing tools
  • βœ•Projects needing an out-of-the-box UI without any custom coding

Example workflow

  1. Install the core Tiptap react and ProseMirror dependencies
  2. Initialize the useEditor hook with the required StarterKit extensions
  3. Set immediatelyRender to false to prevent Next.js hydration mismatches
  4. Apply Tailwind prose classes to the editor container for typography
  5. Implement an image upload handler to replace base64 previews with remote URLs
  6. Render the EditorContent component within the application layout

Prerequisites

  • –React 19+
  • –Tailwind v4
  • –Basic understanding of ProseMirror schema concepts

Pitfalls & limitations

  • !Neglecting the immediatelyRender: false flag causes frequent SSR hydration crashes
  • !Using Base64 for images bloats JSON payloads and degrades performance
  • !Incorrect extension load order can lead to unexpected formatting behavior
  • !Overloading the editor with too many custom extensions increases bundle size

FAQ

Why is my editor crashing in Next.js?
You are likely hitting an SSR hydration mismatch. Set the 'immediatelyRender' property to 'false' in your 'useEditor' configuration.
Can I use Tiptap without Tailwind?
Yes, Tiptap is headless. You can style the editor by writing custom CSS for the '.tiptap' class or by passing your own styles to the editorProps.
Should I store images as base64 strings?
No, this is highly inefficient. Store images on a remote bucket like R2 and only save the resulting URL in your JSON document.
What is the difference between StarterKit and individual extensions?
StarterKit is a convenient bundle of the 20 most essential extensions; individual extensions allow for a smaller footprint by including only what your project needs.

How it compares

Tiptap offers programmatic control over document nodes that a simple textarea or basic HTML contentEditable element cannot match, providing a structured JSON output instead of raw, fragile HTML strings.

Source & trust

⭐ 860 starsπŸ“„ MITπŸ•’ Updated 2026-06-11
πŸ“„ Full skill instructions β€” original source: jezweb/claude-skills
# Tiptap Rich Text Editor

**Status**: Production Ready
**Last Updated**: 2026-01-21
**Dependencies**: React 19+, Tailwind v4, shadcn/ui (recommended)
**Latest Versions**: @tiptap/[email protected], @tiptap/[email protected], @tiptap/[email protected] (verified 2026-01-21)

---

## Quick Start (5 Minutes)

### 1. Install Dependencies

npm install @tiptap/react @tiptap/starter-kit @tiptap/pm @tiptap/extension-image @tiptap/extension-color @tiptap/extension-text-style @tiptap/extension-typography


**Why this matters:**
- @tiptap/pm is required peer dependency (ProseMirror engine)
- StarterKit bundles 20+ essential extensions (headings, lists, bold, italic, etc.)
- Image/color/typography are common additions not in StarterKit

**Important**: If using Tiptap v3.14.0+, drag handle functionality requires minimum v3.14.0 (regression fixed in that release). For Pro extensions with drag handles, React 18 is recommended due to tippyjs-react dependency.

### 2. Create SSR-Safe Editor

import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'

export function Editor() {
const editor = useEditor({
extensions: [StarterKit],
content: '<p>Hello World!</p>',
immediatelyRender: false, // ⚠️ CRITICAL for SSR/Next.js
editorProps: {
attributes: {
class: 'prose prose-sm focus:outline-none min-h-[200px] p-4',
},
},
})

return <EditorContent editor={editor} />
}


**CRITICAL:**
- **Always set immediatelyRender: false** for Next.js/SSR apps (prevents hydration mismatch)
- Without this, you'll see: "SSR has been detected, please set immediatelyRender explicitly to false"
- This is the #1 error reported by Tiptap users

### 3. Add Tailwind Typography (Optional but Recommended)

npm install @tailwindcss/typography


Update your tailwind.config.ts:
import typography from '@tailwindcss/typography'

export default {
plugins: [typography],
}


**Why this matters:**
- Provides default prose styling for headings, lists, links, etc.
- Without it, formatted content looks unstyled
- Alternative: Use custom Tailwind classes with .tiptap selector

---

## The 3-Step Setup Process

### Step 1: Choose Your Integration Method

**Option A: shadcn Minimal Tiptap Component (Recommended)**

Install the pre-built shadcn component:
npx shadcn@latest add https://raw.githubusercontent.com/Aslam97/shadcn-minimal-tiptap/main/registry/block-registry.json


This installs:
- Fully-featured editor component with toolbar
- Image upload support
- Code block with syntax highlighting
- Typography extension configured
- Dark mode support

**Option B: Build Custom Editor (Full Control)**

Use templates from this skill:
- templates/base-editor.tsx - Minimal editor setup
- templates/common-extensions.ts - Extension bundle
- templates/tiptap-prose.css - Tailwind styling

**Key Points:**
- Option A: Faster setup, opinionated UI
- Option B: Complete customization, headless approach
- Both work with React + Tailwind v4

### Step 2: Configure Extensions

Extensions add functionality to your editor:

import StarterKit from '@tiptap/starter-kit'
import Image from '@tiptap/extension-image'
import Link from '@tiptap/extension-link'
import Typography from '@tiptap/extension-typography'

const editor = useEditor({
extensions: [
StarterKit.configure({
// Customize built-in extensions
heading: {
levels: [1, 2, 3],
},
bulletList: {
keepMarks: true,
},
}),
Image.configure({
inline: true,
allowBase64: false, // ⚠️ Prevent base64 bloat
resize: {
enabled: true,
directions: ['top-right', 'bottom-right', 'bottom-left', 'top-left'],
minWidth: 100,
minHeight: 100,
alwaysPreserveAspectRatio: true,
},
}),
Link.configure({
openOnClick: false,
HTMLAttributes: {
class: 'text-primary underline',
},
}),
Typography, // Smart quotes, dashes, etc.
],
})


**CRITICAL:**
- Set allowBase64: false to prevent huge JSON payloads
- Use upload handler pattern (see templates/image-upload-r2.tsx)
- Extension order matters - dependencies must load first

### Step 3: Handle Image Uploads (If Needed)

**Pattern**: Base64 preview β†’ background upload β†’ replace with URL

See templates/image-upload-r2.tsx for full implementation:

import { Editor } from '@tiptap/core'

async function uploadImageToR2(file: File, env: Env): Promise<string> {
// 1. Create base64 preview for immediate display
const reader = new FileReader()
const base64 = await new Promise<string>((resolve) => {
reader.onload = () => resolve(reader.result as string)
reader.readAsDataURL(file)
})

// 2. Insert preview into editor
editor.chain().focus().setImage({ src: base64 }).run()

// 3. Upload to R2 in background
const formData = new FormData()
formData.append('file', file)

const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
})

const { url } = await response.json()

// 4. Replace base64 with permanent URL
editor.chain()
.focus()
.updateAttributes('image', { src: url })
.run()

return url
}


**Why this pattern:**
- Immediate user feedback (preview)
- No database bloat from base64
- Works with Cloudflare R2
- Graceful error handling

---

## Critical Rules

### Always Do

βœ… Set immediatelyRender: false in useEditor() for SSR apps
βœ… Install @tailwindcss/typography for prose styling
βœ… Use upload handler for images (not base64)
βœ… Memoize editor configuration to prevent re-renders
βœ… Include @tiptap/pm peer dependency

### Never Do

❌ Use immediatelyRender: true (default) with Next.js/SSR
❌ Store images as base64 in database (use URL after upload)
❌ Forget to add prose classes to editor container
❌ Load more than 100 widgets in collaborative mode
❌ Use Create React App (v3 incompatible - use Vite)

---

## Known Issues Prevention

This skill prevents **7** documented issues:

### Issue #1: SSR Hydration Mismatch
**Error**: "SSR has been detected, please set immediatelyRender explicitly to false"
**Source**: [GitHub Issue #5856](https://github.com/ueberdosis/tiptap/issues/5856), [#5602](https://github.com/ueberdosis/tiptap/issues/5602)
**Why It Happens**: Default immediatelyRender: true breaks Next.js hydration
**Prevention**: Template includes immediatelyRender: false by default

### Issue #2: Editor Re-renders on Every Keystroke
**Error**: Laggy typing, poor performance in large documents
**Source**: [Tiptap Performance Docs](https://tiptap.dev/docs/editor/api/editor#immediatelyrender)
**Why It Happens**: useEditor() hook re-renders component on every change
**Prevention**: Use useEditorState() hook or memoization patterns (see templates)

### Issue #3: Tailwind Typography Not Working
**Error**: Headings/lists render unstyled, no formatting visible
**Source**: [shadcn Tiptap Discussion](https://github.com/shadcn-ui/ui/discussions/1729)
**Why It Happens**: Missing @tailwindcss/typography plugin
**Prevention**: Skill includes typography plugin installation in checklist

### Issue #4: Image Upload Base64 Bloat
**Error**: JSON payloads become megabytes, slow saves, database bloat
**Source**: [Tiptap Image Docs](https://tiptap.dev/docs/editor/extensions/nodes/image#usage)
**Why It Happens**: Default allows base64, no upload handler configured
**Prevention**: R2 upload template with URL replacement pattern

### Issue #5: Build Errors in Create React App
**Error**: "jsx-runtime" module resolution errors after upgrading to v3
**Source**: [GitHub Issue #6812](https://github.com/ueberdosis/tiptap/issues/6812)
**Why It Happens**: CRA incompatibility with v3 module structure
**Prevention**: Skill documents Vite as preferred bundler + provides working config

### Issue #6: ProseMirror Multiple Versions Conflict
**Error**: Error: Looks like multiple versions of prosemirror-model were loaded
**Source**: [GitHub Issue #577](https://github.com/ueberdosis/tiptap/issues/577) (131 comments), [Issue #6171](https://github.com/ueberdosis/tiptap/issues/6171)
**Why It Happens**: Installing additional Tiptap extensions can pull different versions of prosemirror-model or prosemirror-view, creating duplicate dependencies in node_modules. The unique-id extension is particularly problematic in testing environments.
**Prevention**: Use package resolutions to force a single ProseMirror version

// package.json
{
"resolutions": {
"prosemirror-model": "~1.21.0",
"prosemirror-view": "~1.33.0",
"prosemirror-state": "~1.4.3"
}
}


Or reinstall dependencies:
rm -rf node_modules package-lock.json
npm install


**Note**: The @tiptap/pm package is designed to prevent this issue, but extensions may still introduce conflicts.

### Issue #7: EditorProvider vs useEditor Confusion (Community-sourced)
**Error**: SSR has been detected, please set 'immediatelyRender' explicitly to 'false' (when both used together)
**Source**: [GitHub Issue #5856 Comment](https://github.com/ueberdosis/tiptap/issues/5856#issuecomment-2493124171)
**Why It Happens**: Users commonly use EditorProvider and useEditor together, but EditorProvider is a wrapper around useEditor for React Context setup - they should not be used simultaneously.
**Prevention**: Choose one pattern only

**Incorrect Pattern**:
// Don't use both together
<EditorProvider>
<MyComponent />
</EditorProvider>

function MyComponent() {
const editor = useEditor({ ... }) // ❌ Wrong - EditorProvider already created editor
}


**Correct Patterns**:
// Option 1: Use EditorProvider only
<EditorProvider immediatelyRender={false} extensions={[StarterKit]}>
<EditorContent />
</EditorProvider>

// Option 2: Use useEditor only
function Editor() {
const editor = useEditor({
extensions: [StarterKit],
immediatelyRender: false,
})
return <EditorContent editor={editor} />
}


---

## Configuration Files Reference

### Tailwind Prose Styling (tiptap-prose.css)

/* Apply to editor container */
.tiptap {
/* Tailwind Typography */
@apply prose prose-sm sm:prose-base lg:prose-lg dark:prose-invert max-w-none;

/* Custom overrides */
h1 {
@apply text-3xl font-bold mt-8 mb-4;
}

h2 {
@apply text-2xl font-semibold mt-6 mb-3;
}

p {
@apply my-4 text-base leading-7;
}

ul, ol {
@apply my-4 ml-6;
}

code {
@apply bg-muted px-1.5 py-0.5 rounded text-sm font-mono;
}

pre {
@apply bg-muted p-4 rounded-lg overflow-x-auto;
}

blockquote {
@apply border-l-4 border-primary pl-4 italic my-4;
}
}


**Why these settings:**
- prose classes provide consistent formatting
- dark:prose-invert handles dark mode automatically
- Custom overrides use semantic Tailwind v4 colors

---

## Common Patterns

### Pattern 1: Collaborative Editing with Y.js

import { useEditor } from '@tiptap/react'
import Collaboration from '@tiptap/extension-collaboration'
import * as Y from 'yjs'

const ydoc = new Y.Doc()

const editor = useEditor({
extensions: [
StarterKit.configure({
history: false, // Disable history for collaboration
}),
Collaboration.configure({
document: ydoc,
}),
],
})


**When to use**: Real-time multi-user editing (Notion-like)
**See**: templates/collaborative-setup.tsx for full example

### Pattern 2: Markdown Support

import { useEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import { Markdown } from '@tiptap/markdown'

// Load editor with markdown content
const editor = useEditor({
extensions: [StarterKit, Markdown],
content: '# Hello World\n\nThis is **Markdown**!',
contentType: 'markdown', // ⚠️ CRITICAL: Must specify or content parsed as HTML
immediatelyRender: false,
})

// Get markdown from editor
const markdownOutput = editor.getMarkdown()

// Insert markdown content
editor.commands.setContent('## New heading', { contentType: 'markdown' })
editor.commands.insertContent('**Bold** text', { contentType: 'markdown' })


**When to use**: Storing content as markdown, displaying/editing rich text
**Install**: npm install @tiptap/[email protected]
**Status**: Beta (released Oct 2025, API stable but may change)
**CRITICAL**: Always specify contentType: 'markdown' when setting markdown content

**Recent Fixes** (v3.15.0-v3.16.0):
- Fixed incorrect Markdown output when underline is mixed with bold/italic and ranges don't fully overlap
- Improved serialization for overlapping formatting marks
- Source: [v3.16.0 Release](https://github.com/ueberdosis/tiptap/releases/tag/v3.16.0)

### Pattern 3: Form Integration with react-hook-form

import { useForm, Controller } from 'react-hook-form'

function BlogForm() {
const { control, handleSubmit } = useForm()

return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="content"
control={control}
render={({ field }) => (
<Editor
content={field.value}
onUpdate={({ editor }) => {
field.onChange(editor.getHTML())
}}
/>
)}
/>
</form>
)
}


**When to use**: Blog posts, comments, any form-based content

---

## Using Bundled Resources

### Scripts (scripts/)

No executable scripts for this skill.

### Templates (templates/)

**Required for all projects:**
- templates/base-editor.tsx - Minimal React editor component
- templates/package.json - Required dependencies

**Optional based on needs:**
- templates/minimal-tiptap-setup.sh - shadcn component installation
- templates/image-upload-r2.tsx - R2 upload handler
- templates/tiptap-prose.css - Tailwind styling
- templates/collaborative-setup.tsx - Y.js collaboration
- templates/common-extensions.ts - Extension bundle

**When to load these**: Claude should reference templates when user asks to:
- Set up tiptap editor
- Add image uploads
- Configure collaborative editing
- Style with Tailwind prose

### References (references/)

- references/tiptap-docs.md - Key documentation links
- references/common-errors.md - Error troubleshooting guide
- references/extension-catalog.md - Popular extensions list

**When Claude should load these**: Troubleshooting errors, exploring extensions, understanding API

---

## Advanced Topics

### Custom Extensions

Create your own Tiptap extensions:

import { Node } from '@tiptap/core'

const CustomNode = Node.create({
name: 'customNode',

group: 'block',

content: 'inline*',

parseHTML() {
return [{ tag: 'div[data-custom]' }]
},

renderHTML({ HTMLAttributes }) {
return ['div', { 'data-custom': '', ...HTMLAttributes }, 0]
},

addCommands() {
return {
insertCustomNode: () => ({ commands }) => {
return commands.insertContent({ type: this.name })
},
}
},
})


**Use cases**: Custom widgets, embeds, interactive elements

### Slash Commands

Add Notion-like / commands:

import { Extension } from '@tiptap/core'
import Suggestion from '@tiptap/suggestion'

const SlashCommands = Extension.create({
name: 'slashCommands',

addOptions() {
return {
suggestion: {
char: '/',
items: ({ query }) => {
return [
{ title: 'Heading 1', command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).setHeading({ level: 1 }).run()
}},
{ title: 'Bullet List', command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).toggleBulletList().run()
}},
]
},
},
}
},

addProseMirrorPlugins() {
return [Suggestion({ editor: this.editor, ...this.options.suggestion })]
},
})


**Use cases**: Productivity shortcuts, quick formatting

---

## Dependencies

**Required**:
- @tiptap/react@^3.16.0 - React integration (React 19 supported)
- @tiptap/starter-kit@^3.16.0 - Essential extensions bundle
- @tiptap/pm@^3.16.0 - ProseMirror peer dependency
- react@^19.0.0 - React framework

**React Version Compatibility**:
- **Core Tiptap**: Supports React 19 as of v2.10.0
- **UI Components**: Work best with React 18 (Next.js 15 recommended per [official docs](https://tiptap.dev/docs/editor/getting-started/install/nextjs))
- **Pro Extensions**: May require React 18 - drag-handle extension depends on archived tippyjs-react without React 19 support ([Issue #5876](https://github.com/ueberdosis/tiptap/issues/5876))

**Optional**:
- @tiptap/extension-audio@^3.16.0 - Audio support (NEW in v3.16.0)
- @tiptap/extension-image@^3.16.0 - Image support
- @tiptap/extension-link@^3.16.0 - Link support (NEW in v3, included in StarterKit)
- @tiptap/extension-color@^3.16.0 - Text color
- @tiptap/extension-typography@^3.16.0 - Smart typography
- @tiptap/extension-collaboration@^3.16.0 - Real-time collaboration
- @tiptap/extension-markdown@^3.16.0 - Markdown support (Beta)
- @tailwindcss/typography@^0.5.19 - Prose styling
- yjs@^13.6.0 - Collaborative editing backend
- react-medium-image-zoom@^5.2.0 - Image zoom functionality

---

## Official Documentation

- **Tiptap**: https://tiptap.dev
- **Installation Guide**: https://tiptap.dev/docs/editor/installation/react
- **Extensions**: https://tiptap.dev/docs/editor/extensions
- **API Reference**: https://tiptap.dev/docs/editor/api/editor
- **shadcn minimal-tiptap**: https://github.com/Aslam97/shadcn-minimal-tiptap
- **Context7 Library ID**: tiptap/tiptap

---

## Package Versions (Verified 2026-01-21)

{
"dependencies": {
"@tiptap/react": "^3.16.0",
"@tiptap/starter-kit": "^3.16.0",
"@tiptap/pm": "^3.16.0",
"@tiptap/extension-audio": "^3.16.0",
"@tiptap/extension-image": "^3.16.0",
"@tiptap/extension-color": "^3.16.0",
"@tiptap/extension-text-style": "^3.16.0",
"@tiptap/extension-typography": "^3.16.0",
"@tiptap/extension-link": "^3.16.0",
"@tiptap/extension-markdown": "^3.16.0"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.19",
"react": "^19.2.3",
"react-dom": "^19.2.3"
}
}


---

## Production Example

This skill is based on real-world implementations:
- **GitLab**: Uses Tiptap for issue/MR descriptions
- **Statamic CMS**: Tiptap as default rich text editor
- **shadcn minimal-tiptap**: 3.14M downloads/week

**Token Savings**: ~71% (14k β†’ 4k tokens)
**Errors Prevented**: 7/7 documented errors (5 critical setup + 2 community patterns)
**Validation**: βœ… SSR compatibility, βœ… Image uploads, βœ… Tailwind v4, βœ… Performance, βœ… React 19 compatibility

---

## Troubleshooting

### Problem: "SSR has been detected, please set immediatelyRender explicitly to false"
**Solution**: Add immediatelyRender: false to your useEditor() config

### Problem: Headings/lists look unstyled
**Solution**: Install @tailwindcss/typography and add prose classes to editor container

### Problem: Editor lags when typing
**Solution**: Use useEditorState() hook instead of useEditor() for read-only rendering, or memoize editor configuration

### Problem: Images make JSON huge
**Solution**: Set allowBase64: false in Image extension config and use upload handler (see templates/image-upload-r2.tsx)

### Problem: Build fails in Create React App
**Solution**: Switch to Vite - CRA incompatible with Tiptap v3. See cloudflare-worker-base skill for Vite setup.

---

## Complete Setup Checklist

Use this checklist to verify your setup:

- [ ] Installed @tiptap/react, @tiptap/starter-kit, @tiptap/pm
- [ ] Set immediatelyRender: false in useEditor() config
- [ ] Installed @tailwindcss/typography plugin
- [ ] Added prose classes to editor container
- [ ] Configured image upload handler (if using images)
- [ ] Set allowBase64: false in Image extension
- [ ] Editor renders without hydration errors
- [ ] Formatted text displays correctly (headings, lists, etc.)
- [ ] Dev server runs without TypeScript errors
- [ ] Production build succeeds

---

**Questions? Issues?**

1. Check references/common-errors.md for troubleshooting
2. Verify immediatelyRender: false is set
3. Check official docs: https://tiptap.dev
4. Ensure @tiptap/pm peer dependency is installed


---

---
paths: "**/*.ts", "**/*.tsx", "**/editor*.ts", "**/tiptap*.ts"
---

# Tiptap v3 Corrections

Claude's training may reference Tiptap v2 patterns. This project uses **Tiptap v3**.

## SSR/Next.js: immediatelyRender Required

/* ❌ v2 default (causes hydration mismatch in SSR) */
const editor = useEditor({
extensions: [StarterKit],
content: '<p>Hello</p>',
})

/* βœ… v3 SSR-safe */
const editor = useEditor({
extensions: [StarterKit],
content: '<p>Hello</p>',
immediatelyRender: false, // CRITICAL for Next.js/SSR
})


**Error without this:** "SSR has been detected, please set immediatelyRender explicitly to false"

## Peer Dependency: @tiptap/pm Required

# ❌ Missing peer dependency (causes runtime errors)
npm install @tiptap/react @tiptap/starter-kit

# βœ… Include ProseMirror engine
npm install @tiptap/react @tiptap/starter-kit @tiptap/pm


## Extension Configuration (v3 Changes)

/* ❌ v2 extension config */
StarterKit.configure({
heading: { levels: [1, 2, 3] },
})

/* βœ… v3 extension config (same API, verify import) */
import StarterKit from '@tiptap/starter-kit'
StarterKit.configure({
heading: { levels: [1, 2, 3] },
})


## Content Change Handler

/* ❌ v2 onUpdate signature */
onUpdate: ({ editor }) => {
const html = editor.getHTML()
}

/* βœ… v3 (same API, but check for transaction) */
onUpdate: ({ editor, transaction }) => {
if (transaction.docChanged) {
const html = editor.getHTML()
onChange?.(html)
}
}


## Image Extension

/* ❌ Old import path */
import Image from '@tiptap/extension-image'

/* βœ… v3 import */
import Image from '@tiptap/extension-image'
Image.configure({
inline: true,
allowBase64: true, // For data URLs
})


## Quick Fixes

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| useEditor({...}) without immediatelyRender | Add immediatelyRender: false for SSR |
| Missing @tiptap/pm | Install @tiptap/pm as peer dependency |
| editor.commands.setContent() in render | Use useEffect or onUpdate callback |
| Direct DOM manipulation | Use editor.chain().focus().insertContent() |
| getHTML() in render | Memoize or use state to avoid re-renders |

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/tiptap/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/jezweb/claude-skills/tiptap/SKILL.md
  • Cursor: ~/.cursor/skills/jezweb/claude-skills/tiptap/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/jezweb/claude-skills/tiptap/SKILL.md

πŸš€ Install with CLI:
npx skills add jezweb/claude-skills

Read the Master Guide: Mastering Agent Skills β†’

Related Skill Units

Recommended Rules

View more rules β†’

Recommended Workflows

View more workflows β†’

Recommended MCP Servers

View more MCP servers β†’

Take It Further

Maximize your productivity with these powerful resources

πŸ“‹

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
πŸ“–

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid react & react native issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under React & React Native and is published by JezWeb, maintained in jezweb/claude-skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.