A modern, feature-rich WYSIWYG rich text editor built with Tiptap and Radix UI for React and Next.js applications.
Try it yourself in this live demo!
- Text Formatting: Bold, italic, underline, strikethrough, code, subscript, superscript
- Headings: Multiple heading levels (H1-H6)
- Lists: Ordered and unordered lists with nested support
- Text Alignment: Left, center, right, and justify alignment
- Text Styling: Custom text color and background highlighting
- Links: Insert and edit hyperlinks with custom text
- Images: Upload, resize, and add captions to images
- Tables: Create and edit tables with cell alignment and formatting
- Code Blocks: Syntax-highlighted code blocks with language selection
- YouTube Embeds: Embed YouTube videos directly in your content
- Drag & Drop: Reorder content blocks with intuitive drag handles
# Clone the repository
git clone https://github.com/ndtrung341/next-tiptap.git
# Navigate to project directory
cd next-tiptap
# Install dependencies
pnpm install
# or
npm install
# or
yarn install# Start development server
pnpm dev
# or
npm run dev
# or
yarn devOpen http://localhost:3000 to see the editor in action.
import TiptapEditor, { type TiptapEditorRef } from "@/components/tiptap-editor";
import { useRef } from "react";
export default function MyEditor() {
const editorRef = useRef<TiptapEditorRef>(null);
const handleChange = (content: string) => {
console.log("Content updated:", content);
};
return (
<TiptapEditor
ref={editorRef}
output="html"
minHeight={320}
maxHeight={640}
onChange={handleChange}
placeholder={{
paragraph: "Start typing...",
imageCaption: "Add a caption (optional)",
}}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
content |
Content |
undefined |
Initial editor content (HTML or JSON) |
output |
"html" | "json" |
"html" |
Output format for content |
readonly |
boolean |
false |
Make editor read-only |
disabled |
boolean |
false |
Disable editor interactions |
minHeight |
string | number |
320 |
Minimum editor height (px) |
maxHeight |
string | number |
undefined |
Maximum editor height (px) |
maxWidth |
string | number |
undefined |
Maximum editor width (px) |
placeholder |
string | Record<string, string> |
undefined |
Placeholder text |
ssr |
boolean |
false |
Enable server-side rendering |
throttleDelay |
number |
1500 |
Throttle delay for onChange (ms) |
onChange |
(content: Content) => void |
undefined |
Callback when content changes |
const editorRef = useRef<TiptapEditorRef>(null);
// Get editor instance
const editor = editorRef.current;
// Get content
const htmlContent = editor?.getHTML();
const jsonContent = editor?.getJSON();
// Get statistics
const wordCount = editor?.storage.characterCount.words();
const charCount = editor?.storage.characterCount.characters();
// Programmatic control
editor?.commands.setContent("<p>New content</p>");
editor?.commands.focus();The editor uses CSS variables for theming. Customize colors in your globals.css:
:root {
--rte-editor-min-height: 320px;
--rte-editor-max-height: 640px;
--rte-editor-max-width: 700px;
}Add or remove Tiptap extensions in src/components/tiptap-editor/extensions/index.ts:
import { Extension } from "@tiptap/core";
export const createExtensions = ({ placeholder }) => [
// Add your custom extensions here
StarterKit,
Image,
Link,
Table,
// ... more extensions
];- Framework: Next.js 15 - App Router
- Editor: Tiptap - Headless editor framework
- UI Components: Radix UI
- Styling: SCSS + Tailwind CSS
- Language: TypeScript
- Form Handling: React Hook Form
- Icons: React Icons
Built with ❤️ using Next.js and Tiptap
