React drag and drop plugin for Plate rich-text editor enabling block rearrangement and file drops
npx @tessl/cli install tessl/npm-udecode--plate-dnd@49.0.0The @udecode/plate-dnd package provides comprehensive drag-and-drop functionality for the Plate rich-text editor. It enables users to rearrange editor blocks through intuitive drag-and-drop interactions, with features including visual drop indicators, automatic viewport scrolling during drag operations, customizable drag handles, and support for file drops to insert media content. The plugin integrates seamlessly with React DnD backend and provides hooks for managing drag states, drop zones, and node interactions.
npm install @udecode/plate-dndimport { DndPlugin, useDndNode, useDraggable, useDropLine } from "@udecode/plate-dnd";For CommonJS:
const { DndPlugin, useDndNode, useDraggable, useDropLine } = require("@udecode/plate-dnd");import { DndPlugin, useDndNode } from "@udecode/plate-dnd";
import { createPlateEditor } from "@udecode/plate/react";
// Configure the plugin
const editor = createPlateEditor({
plugins: [
DndPlugin.configure({
options: {
enableScroller: true,
onDropFiles: ({ id, dragItem, editor, target }) => {
// Handle file drops to insert media
console.log('File dropped:', dragItem.files);
}
}
})
]
});
// Use in a block component
function DraggableBlock({ element, children }) {
const { dragRef, isDragging, isOver } = useDndNode({
element,
orientation: 'vertical'
});
return (
<div
ref={dragRef}
style={{ opacity: isDragging ? 0.5 : 1 }}
>
{children}
</div>
);
}The @udecode/plate-dnd package is built around several key components:
DndPlugin integrating with Plate's plugin architectureThe core DndPlugin that integrates drag-and-drop functionality into Plate editors, with configurable options for behavior customization.
export const DndPlugin: PlatePlugin<DndConfig>;
export type DndConfig = PluginConfig<
'dnd',
{
draggingId?: string | null;
dropTarget?: {
id: string | null;
line: DropLineDirection;
};
enableScroller?: boolean;
isDragging?: boolean;
scrollerProps?: Partial<ScrollerProps>;
onDropFiles?: (props: {
id: string;
dragItem: FileDragItemNode;
editor: PlateEditor;
monitor: DropTargetMonitor<DragItemNode, unknown>;
nodeRef: any;
target?: Path;
}) => void;
}
>;
export const DRAG_ITEM_BLOCK = 'block';React hooks for implementing drag-and-drop behavior on editor nodes, with support for both dragging and dropping functionality.
export function useDndNode(options: UseDndNodeOptions): {
dragRef: ConnectDragSource;
isDragging: boolean;
isOver: boolean;
};
export function useDragNode(
editor: PlateEditor,
options: UseDragNodeOptions
): [{ isDragging: boolean }, ConnectDragSource, ConnectDragPreview];
export function useDropNode(
editor: PlateEditor,
options: UseDropNodeOptions
): [{ isOver: boolean }, ConnectDropTarget];Pre-built components and hooks for common drag-and-drop UI patterns including draggable elements and drop line indicators.
export function useDraggable(props: UseDndNodeOptions): DraggableState;
export function useDropLine(options?: {
id?: string;
orientation?: 'horizontal' | 'vertical';
}): {
dropLine?: DropLineDirection;
};
export type DraggableState = {
isDragging: boolean;
previewRef: React.RefObject<HTMLDivElement | null>;
handleRef: (elementOrNode: Element | React.ReactElement<any> | React.RefObject<any> | null) => void;
};Components that provide automatic viewport scrolling when dragging near screen edges, enhancing user experience during drag operations.
export function DndScroller(props: Partial<ScrollerProps>): JSX.Element;
export function Scroller(props: ScrollerProps): JSX.Element;
export function ScrollArea({
placement,
containerRef,
enabled,
height,
minStrength,
scrollAreaProps,
strengthMultiplier,
zIndex
}: ScrollAreaProps): JSX.Element | null;Functions for manipulating editor state during drag-and-drop operations, including block selection, movement, and focus management.
export function selectBlocksBySelectionOrId(editor: PlateEditor, id: string): void;
export function selectBlockById(editor: Editor, id: string): void;
export function removeBlocksAndFocus<E extends Editor = Editor>(
editor: E,
options: EditorNodesOptions<ValueOf<E>>
): void;
export function focusBlockStartById(editor: Editor, id: string): void;
export function onDropNode(
editor: PlateEditor,
options: OnDropNodeOptions
): void;Helper functions for calculating drop directions, handling hover states, and determining valid drop operations.
export function getHoverDirection(options: GetHoverDirectionOptions): string;
export function getNewDirection(
previousDir: string,
dir?: string
): DropLineDirection | undefined;
export function getBlocksWithId<E extends Editor>(
editor: E,
options: EditorNodesOptions<ValueOf<E>>
): NodeEntry<TElement>[];export type DragItemNode = ElementDragItemNode | FileDragItemNode;
export type DropDirection = 'bottom' | 'left' | 'right' | 'top' | undefined;
export type DropLineDirection = '' | 'bottom' | 'left' | 'right' | 'top';
export interface ElementDragItemNode {
id: string;
element: TElement;
[key: string]: unknown;
}
export interface FileDragItemNode {
dataTransfer: DataTransfer[];
files: FileList;
items: DataTransferItemList;
}