After installation, import the editor styles at the root of your application:
Copy// Your shadcn globalsimport "@editorcn/ui/globals.css";// Block editor stylesimport "@editorcn/block-editor/style.css";
If you installed via the shadcn registry, the package is copied into your project, so import from your local components path instead of @editorcn/block-editor throughout this page:
Copyimport { BlockEditor, SlashCommand, defaultSlashCommandItems, getSlashCommandSuggestion,} from "@/components/block-editor";import "@/components/block-editor/style.css";
Copy"use client";import { useEditor } from "@tiptap/react";import StarterKit from "@tiptap/starter-kit";import Placeholder from "@tiptap/extension-placeholder";import Underline from "@tiptap/extension-underline";import TaskList from "@tiptap/extension-task-list";import TaskItem from "@tiptap/extension-task-item";import Image from "@tiptap/extension-image";import Table from "@tiptap/extension-table";import TableRow from "@tiptap/extension-table-row";import TableCell from "@tiptap/extension-table-cell";import TableHeader from "@tiptap/extension-table-header";import { BlockEditor, SlashCommand, defaultSlashCommandItems, getSlashCommandSuggestion,} from "@editorcn/block-editor";import type { SlashCommandSuggestionItem } from "@editorcn/block-editor";const myItems: SlashCommandSuggestionItem[] = [ ...defaultSlashCommandItems, { id: "image", title: "Image", description: "Insert an image.", keywords: ["image", "img", "picture", "photo"], command: ({ editor, range }) => { const url = window.prompt("Enter image URL"); // Replace with your own dialog component if (!url) return; editor.chain().focus().deleteRange(range).setImage({ src: url }).run(); }, }, { id: "table", title: "Table", description: "Insert a table.", keywords: ["table", "grid"], command: ({ editor, range }) => { editor .chain() .focus() .deleteRange(range) .insertTable({ rows: 3, cols: 3, withHeaderRow: true }) .run(); }, },];function MyBlockEditor() { const editor = useEditor({ immediatelyRender: false, extensions: [ StarterKit.configure({ heading: { levels: [1, 2, 3] }, }), Placeholder.configure({ placeholder: "Type / for commands..." }), Underline, TaskList, TaskItem.configure({ nested: true }), Table, TableRow, TableCell, TableHeader, Image, SlashCommand.configure({ suggestion: getSlashCommandSuggestion(myItems), }), ], }); return <BlockEditor editor={editor} />;}
BlockEditor (Root)
The root wrapper that provides editor context. Renders the full editor UI by default (drag handle, block actions, bubble menu, and content area) or accepts custom children.
Props
Prop
Type
Default
Description
editor
Editor | null
—
The Tiptap editor instance
children
ReactNode
—
Optional custom children to replace the default layout
className
string
—
Additional CSS classes
labels
Partial<BlockEditorLabels>
DEFAULT_BLOCK_EDITOR_LABELS
Override default slash command labels
Labels
Key
Default
Description
paragraphLabel
"Text"
Label for paragraph node
headingLabel
"Heading"
Label for heading nodes
bulletListLabel
"Bullet list"
Label for bullet list
orderedListLabel
"Numbered list"
Label for ordered list
taskListLabel
"To-do list"
Label for task list
blockquoteLabel
"Quote"
Label for blockquote
codeBlockLabel
"Code"
Label for code block
dividerLabel
"Divider"
Label for divider
BlockEditor.Content
Renders the editor content area with the drag handle and block actions. Use this when providing custom children to the root.
A standalone bubble menu component that can be used outside the BlockEditor root. Useful if you want to customize the bubble menu position or behavior.
The bubble menu automatically positions itself near the selection and is styled with your theme's --popover tokens.
Block actions
Click the drag handle (grip icon) on the left side of any block to access a dropdown with:
Copy — Copy the current block content to clipboard
Delete — Delete the current block
Drag handle
Drag blocks to reorder them using the grip icon on the left. The drag handle uses @tiptap/extension-drag-handle-react.
Extensions
All @tiptap/* packages are peer dependencies — you must install them in your project. This ensures there is only one copy of Tiptap's types, avoiding "duplicate instance" TypeScript errors. If you installed via the shadcn registry, the CLI will prompt you to add any missing peer dependencies automatically.
Extension
Purpose
Required
@tiptap/starter-kit
Core editor functionality
Yes
@tiptap/pm
ProseMirror runtime
Yes
@tiptap/react
React bindings
Yes
@tiptap/suggestion
Slash command suggestion engine
Yes
@tiptap/extension-drag-handle-react
Block drag handle UI
Yes
@tiptap/extension-code-block-lowlight
Syntax highlighting (requires lowlight)
Optional
@tiptap/extension-placeholder
Placeholder text
Optional
Extensions for Image, Table, Link, and others are not included — add them as needed for your custom slash commands.
Syntax highlighting
To enable syntax highlighting in code blocks, install lowlight and pass it to @tiptap/extension-code-block-lowlight: