Overview
The Block DnD components provide drag-and-drop functionality for reordering blocks in your editor. Built on top of @dnd-kit, it integrates seamlessly with therenderBlock API to keep DnD logic outside the core editor.

Features
- @dnd-kit powered — industry-standard drag and drop library
- Multi-block selection — drag multiple selected blocks at once
- Visual feedback — drop indicators and drag overlays
- Accessible — keyboard support built-in
- Customizable — style drag handles and drop indicators
- Non-invasive — uses
renderBlockAPI, no core editor changes
Installation
@yoopta/ui package includes @dnd-kit as a dependency.
Quick Start
How It Works
The Block DnD system consists of three main parts:- BlockDndContext — Wraps the editor, provides DnD context and handles block reordering
- SortableBlock — Wrapper for each block that makes it sortable. When using
DragHandle, setuseDragHandle={true}to prevent the entire block from being draggable - DragHandle — The draggable trigger element. Must be used with
SortableBlockthat hasuseDragHandle={true}
renderBlock prop on YooptaEditor allows you to wrap each block with DnD components without modifying the core editor.
Important: When using DragHandle, you must set useDragHandle={true} on SortableBlock. This ensures that drag listeners are only applied to the handle, not the entire block.
API Reference
BlockDndContext
The root provider that wraps your editor and handles drag events.
| Prop | Type | Description |
|---|---|---|
editor | YooEditor | The Yoopta editor instance |
children | ReactNode | Editor and other components |
onDragStart | (event: DragStartEvent) => void | Called when drag starts |
onDragEnd | (event: DragEndEvent) => void | Called when drag ends |
SortableBlock
Wrapper component that makes a block sortable.
| Prop | Type | Description |
|---|---|---|
id | string | Block ID (required) |
children | ReactNode | Block content |
disabled | boolean | Disable sorting for this block |
className | string | Custom CSS classes |
useDragHandle | boolean | If true, listeners won’t be applied to the block (use DragHandle instead). Required when using DragHandle |
DragHandle
The draggable trigger component. Users drag this to move blocks.
| Prop | Type | Description |
|---|---|---|
blockId | string | null | Block ID this handle controls |
children | ReactNode | Handle content (usually an icon) |
className | string | Custom CSS classes |
onClick | (e: MouseEvent) => void | Called when handle is clicked (not dragged) |
asChild | boolean | If true, merges props and event handlers with the child element (useful for integrating with other button components) |
useBlockDnd
Hook for accessing DnD state and utilities.
| Property | Type | Description |
|---|---|---|
activeId | string | null | Currently dragged block ID |
activeBlock | YooptaBlockData | null | Currently dragged block data |
isDragging | boolean | Whether a drag is in progress |
draggedIds | string[] | All block IDs being dragged (for multi-select) |
useBlockDndContext
Hook to access the DnD context value directly.
getOrderedBlockIds
Utility function to get block IDs sorted by their order.
Examples
Basic Setup
With FloatingBlockActions
Integrate DnD with the existing FloatingBlockActions component:Multi-Block Drag
When blocks are selected (via Shift+Click or SelectionBox), dragging one will move all selected blocks:Read-Only Mode
Disable DnD in read-only mode:Styling
CSS Variables
Custom Styles
The renderBlock API
The renderBlock prop on YooptaEditor is the key to integrating DnD without modifying the core editor.
- Add DnD support
- Add custom block wrappers
- Implement block-level features without forking the editor
Best Practices
Memoize renderBlock
Memoize renderBlock
Always wrap
renderBlock in useCallback to prevent unnecessary re-renders:Place BlockDndContext outside YooptaEditor
Place BlockDndContext outside YooptaEditor
The context must wrap the entire editor:
Handle read-only mode
Handle read-only mode
Disable drag handles and sorting in read-only mode: