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-menuComponents
<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-buttonduplicate-buttoncopy-to-clipboard-buttondelete-node-buttonreset-all-formatting-buttonslash-command-trigger-buttoncolor-text-buttoncolor-highlight-buttonai-ask-buttontext-buttonheading-buttonlist-buttonblockquote-buttoncode-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