Drag Context Menu
A fully accessible drag context menu for Tiptap editors. Provides a drag handle with an extensive context menu for block-level operations including transforming nodes, styling content, copying, duplicating, and deleting blocks.
Installation
Add the component via the Tiptap CLI:
npx @tiptap/cli@latest add drag-context-menu
Components
<DragContextMenu />
A prebuilt React component that renders a drag handle with a comprehensive context menu for block operations.
Usage
import { EditorContent, EditorContext, useEditor } from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import { DragContextMenu } from '@/components/tiptap-ui/drag-context-menu'
import '@/components/tiptap-node/paragraph-node/paragraph-node.scss'
export default function MyEditor() {
const editor = useEditor({
immediatelyRender: false,
extensions: [StarterKit],
content: `
<h1>Drag Context Menu Demo</h1>
<p>Hover over any block to see the drag handle appear on the left side.</p>
<blockquote>
<p>Click the drag handle to access the context menu with various options.</p>
</blockquote>
`,
})
return (
<EditorContext.Provider value={{ editor }}>
<EditorContent editor={editor} role="presentation" />
<DragContextMenu editor={editor} withSlashCommandTrigger={true} />
</EditorContext.Provider>
)
}
Props
Name | Type | Default | Description |
---|---|---|---|
editor | Editor | null | undefined | The Tiptap editor instance |
withSlashCommandTrigger | boolean | true | Shows a slash command trigger button alongside the drag handle |
The component also accepts all props from DragHandleProps
(excluding editor
and children
).
Hooks
useMenuActionVisibility()
A custom hook that determines which action groups should be visible in the context menu based on the current editor state and selected node.
Usage
function MyCustomDragMenu() {
const { hasAnyActionGroups, hasColorActions, hasTransformActions, hasResetFormatting, hasImage } =
useMenuActionVisibility(editor)
return (
<div>
{hasColorActions && <ColorActions />}
{hasTransformActions && <TransformActions />}
{hasResetFormatting && <ResetFormattingAction />}
{hasImage && <ImageActions />}
</div>
)
}
Props
Name | Type | Default | Description |
---|---|---|---|
editor | Editor | null | undefined | The Tiptap editor instance |
Return Values
Name | Type | Description |
---|---|---|
hasAnyActionGroups | boolean | Whether any action groups should be rendered |
hasColorActions | boolean | Whether color and highlight actions are available |
hasTransformActions | boolean | Whether node transformation actions are available |
hasResetFormatting | boolean | Whether reset formatting action is available |
hasImage | boolean | Whether image-specific actions are available |
Context Menu Features
The drag context menu provides several action groups:
Color Actions
- Text Color: Change text color with recent color history
- Highlight Color: Apply background highlights with color options
Transform Actions
Transform the current block into different node types:
- Text: Convert to paragraph
- Heading 1, 2, 3: Convert to different heading levels
- Bullet List: Convert to unordered list
- Numbered List: Convert to ordered list
- Task List: Convert to task/checkbox list
- Blockquote: Convert to blockquote
- Code Block: Convert to code block
Core Actions
- Ask AI: Trigger AI assistance for the selected content
- Copy: Copy the block content to clipboard
- Duplicate: Create a duplicate of the current block
Reset Formatting
- Reset All Formatting: Remove all formatting marks from the content
Image Actions (for image nodes)
- Download: Download the image file
Delete Actions
- Delete: Remove the current block
Utilities
getNodeDisplayName(editor)
Gets a user-friendly display name for the currently selected node.
import { getNodeDisplayName } from '@/lib/tiptap-collab-utils'
const displayName = getNodeDisplayName(editor) // Returns "text", "Heading 1", "Blockquote", etc.
isTextSelectionValid(editor)
Checks if the current selection is a valid text selection.
import { isTextSelectionValid } from '@/lib/tiptap-collab-utils'
const isValidSelection = isTextSelectionValid(editor)
Behavior
Drag Handle Positioning
- The drag handle appears on hover over block elements
- Automatically positions itself relative to the block height
- For blocks taller than 40px, aligns to the top
- For smaller blocks, centers vertically
Mobile Behavior
- Automatically hides on mobile devices to prevent interface conflicts
- Touch interactions are optimized for mobile editing
AI Integration
- Hides when AI generation is active to prevent interface conflicts
- Provides AI ask functionality through the context menu
Requirements
Dependencies
@tiptap/react
- Core Tiptap React integration@tiptap/extension-drag-handle-react
- Drag handle functionality@floating-ui/react
- Positioning utilitiesreact-hotkeys-hook
- Keyboard shortcut management
Referenced Components
use-tiptap-editor
(hook)use-mobile
(hook)use-ui-editor-state
(hook)button
,button-group
(primitives)menu
,menu-content
,menu-item
(primitives)separator
,spacer
(primitives)combobox
(primitive)
Referenced UI Components
image-download-button
duplicate-button
copy-to-clipboard-button
delete-node-button
reset-all-formatting-button
slash-command-trigger-button
color-text-button
color-highlight-button
ai-ask-button
text-button
heading-button
list-button
blockquote-button
code-block-button
Icons
grip-vertical-icon
- Main drag handle iconpaint-bucket-icon
- Color actionschevron-right-icon
- Submenu indicatorsrepeat-2-icon
- Reset formattingtext-color-small-icon
- Text color