Tiptap drag handle: move the intended block without moving its parent

Enable Tiptap's DragHandle extension to give authors a place to grab document blocks. For a checklist with nested items, enable its nested behavior deliberately and inspect which node the handle targets before moving it. A handle beside a sentence can target the whole list if the selection rules prefer its parent. DragHandle configuration

Consider an original workshop checklist with two sections, “Before opening” and “After closing.” An author wants to move only “Return the spare keys” within the closing list. Moving the entire closing section would change a different instruction sequence, even if the drag animation looked smooth.

Add a handle to the existing editor

In an application with compatible Tiptap packages, a working schema, and its usual editor setup:

import DragHandle from '@tiptap/extension-drag-handle';

const checklistHandle = DragHandle.configure({
  render: () => {
    const handle = document.createElement('div');
    handle.className = 'checklist-drag-handle';
    handle.textContent = '⋮⋮';
    handle.title = 'Drag this block';
    return handle;
  },
  nested: {
    allowedContainers: ['bulletList', 'orderedList'],
    edgeDetection: 'left'
  }
});

Include checklistHandle once in that editor's extensions. This fragment configures the drag interface; it does not create the editor, define list nodes, or implement a keyboard move control. Keep packages compatible with the installed Tiptap version. For a React integration, follow the separate DragHandle React component rather than installing both integrations for the same handle.

Give the handle room beside the text. In the application's editor stylesheet, for example:

.tiptap { padding-left: 3rem; }
.checklist-drag-handle {
  cursor: grab;
  padding: 0.25rem;
  color: #344844;
}

Check that padding against the actual scroll container and mobile layout. A handle positioned outside a clipped container can exist without being reachable.

Decide whether the author means an item or its container

The extension normally targets top-level blocks. Its nested mode considers content inside containers too. The configuration above restricts nested handling to bullet and ordered lists; it does not prohibit dragging ordinary top-level blocks.

With left-edge detection, pointing near an edge can favor a parent. Moving the pointer further inside the item may select the nested node instead. That distinction lets an author move a complete list or one item, but the UI must make the current target understandable.

During integration, use the documented onNodeChange callback to observe the current node and position. Treat those observations as transient: the target can change as the pointer moves. Do not capture one position at startup and reuse it for later document operations.

The ProseMirror dropcursor guide addresses the line showing a possible destination. The handle supplies the source interaction. Inspect both ends of the move: the intended source node and the accepted destination.

Lock visibility only while the handle's menu needs it

If a menu attached to the handle needs to remain visible while the pointer moves into it, use lockDragHandle() and release it with unlockDragHandle() when the menu closes. The lock preserves the handle's position and visibility state. It is not a document permission lock and does not make the checklist read-only.

Avoid a menu that silently retains an earlier node after the document changes. Close it or resolve its target through the application's current editor state before applying an operation. A menu label should describe the block it will affect.

Check the saved order, then provide another way to move

For the workshop fixture, move the spare-keys item above “Switch off the lamps.” Confirm that both remain inside “After closing,” that “Before opening” stays in place, and that the spare-keys text appears once. Then undo and verify the original order.

Also try targeting the complete closing list. The interface should make that larger selection apparent before release. Cancel a drag and confirm nothing changes. Save and reopen through the application's real persistence path; the saved document must retain the accepted order.

A pointer handle alone does not provide an equivalent keyboard operation. Supply an accessible move-up/move-down action through your application's document commands if authors need to reorder without dragging. Finish when both routes move the intended unit and reopening preserves its position.

Keep reading