# How to Implement Drag and Drop Functionality Between Widgets in ImGui

> Learn to implement drag and drop between ImGui widgets. Use BeginDragDropSource, SetDragDropPayload, and BeginDragDropTarget to transfer custom data easily. Master ImGui's drag and drop system today.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-15

---

**Dear ImGui provides a lightweight, immediate-mode drag and drop system using `BeginDragDropSource()`, `SetDragDropPayload()`, and `BeginDragDropTarget()` to transfer custom data between any widgets.**

The drag and drop functionality between widgets in ImGui is defined in the public header [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (around line 976) and implemented in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp). This stateless API allows you to attach custom payloads to any widget and accept them on any other, making it ideal for rearranging lists, creating node graphs, or moving items between panels.

## Understanding the Drag and Drop Architecture

The ImGui drag and drop system is built around three core concepts that work together to create a seamless user experience.

### The Three Core Components

Every drag operation involves:

1. **Drag Source** – The widget that initiates the drag, defined by wrapping its rendering code with `BeginDragDropSource()` and `EndDragDropSource()`.
2. **Payload** – The user-defined data attached via `SetDragDropPayload()`, stored in an `ImGuiPayload` structure (defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 199).
3. **Drop Target** – The destination widget that receives the payload, created using `BeginDragDropTarget()` and `EndDragDropTarget()`.

### State Management

Unlike retained-mode GUI libraries, ImGui's drag and drop system is completely **stateless** from the library's perspective. The payload lives only while the mouse button is held down (or until explicitly released), meaning you don't need to maintain complex state machines to track drag operations across frames.

## Implementing a Drag Source

To make a widget draggable, you must call `BeginDragDropSource()` immediately after submitting the item. This function returns `true` only when the user is actively dragging the item.

```cpp
// Submit the draggable item
if (ImGui::Selectable("Item Label")) {
    // Handle selection click
}

// Set up drag source
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
    // Define the payload type and data
    int item_id = 42;
    ImGui::SetDragDropPayload("MY_ITEM", &item_id, sizeof(int));
    
    // Optional: Display tooltip while dragging
    ImGui::Text("Dragging Item %d", item_id);
    
    ImGui::EndDragDropSource();
}

```

**Key details:**
- `SetDragDropPayload()` takes a null-terminated string identifier (e.g., `"MY_ITEM"`) that targets will use to filter accepted types.
- The payload data is copied into an internal buffer managed by ImGui, so you don't need to keep the original variable alive.
- You must call `EndDragDropSource()` only if `BeginDragDropSource()` returned true.

## Creating a Drop Target

Any widget can become a drop target by wrapping it with `BeginDragDropTarget()`. According to the source code in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), this function checks if a compatible payload is hovering over the last submitted item's bounding box.

```cpp
// Submit the potential drop target
ImGui::Button("Drop Zone");

if (ImGui::BeginDragDropTarget()) {
    // Check for specific payload type
    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_ITEM")) {
        // Verify data size before casting
        IM_ASSERT(payload->DataSize == sizeof(int));
        int received_id = *static_cast<const int*>(payload->Data);
        
        // Handle the drop action
        OnItemDropped(received_id);
    }
    
    ImGui::EndDragDropTarget();
}

```

**Important:** Always verify `payload->DataSize` matches your expected type before casting the void pointer to prevent memory corruption.

## Advanced Configuration and Flags

The API provides several flags in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 976-1002) to customize behavior for complex interactions.

### Suppressing Preview Tooltips

By default, ImGui shows a tooltip with "..." while dragging. To disable this or provide a custom preview:

```cpp
// Disable default tooltip
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoPreviewTooltip)) {
    ImGui::SetDragDropPayload("MY_ITEM", &data, sizeof(data));
    // Custom preview Tooltip
    ImGui::Text("Custom Preview");
    ImGui::EndDragDropSource();
}

```

### Conditional Payload Lifetime

Normally, the payload disappears when the source widget stops being rendered. To keep the payload alive after the source disappears (useful for dragging from toolbars that scroll away), pass `ImGuiCond_Once` or `ImGuiCond_Always` as the fourth parameter to `SetDragDropPayload()`:

```cpp
ImGui::SetDragDropPayload("TOOLBAR_ITEM", &data, sizeof(data), ImGuiCond_Once);

```

### Accepting Payloads Before Delivery

For "drag-over" previews while the mouse button is still held, use `ImGuiDragDropFlags_AcceptBeforeDelivery`:

```cpp
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(
    "MY_ITEM", ImGuiDragDropFlags_AcceptBeforeDelivery)) {
    // Preview mode: payload is valid but mouse button not released yet
}

```

## Complete Working Example

This example demonstrates moving items between two lists, referencing the implementation patterns found in [`examples/example_demo.cpp`](https://github.com/ocornut/imgui/blob/main/examples/example_demo.cpp):

```cpp
static int left_items[] = {1, 2, 3};
static int right_items[] = {4, 5, 6};

// Left list (Drag sources)
ImGui::BeginGroup();
for (int i = 0; i < IM_ARRAYSIZE(left_items); i++) {
    ImGui::PushID(i);
    ImGui::Selectable("Item %d", left_items[i]);
    
    if (ImGui::BeginDragDropSource()) {
        ImGui::SetDragDropPayload("DND_ITEM", &left_items[i], sizeof(int));
        ImGui::Text("Moving Item %d", left_items[i]);
        ImGui::EndDragDropSource();
    }
    ImGui::PopID();
}
ImGui::EndGroup();

ImGui::SameLine();

// Right list (Drop target)
ImGui::BeginGroup();
ImGui::Button("Drop Here", ImVec2(100, 200));
if (ImGui::BeginDragDropTarget()) {
    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_ITEM")) {
        int new_item = *static_cast<const int*>(payload->Data);
        // Add to right_items array...
    }
    ImGui::EndDragDropTarget();
}
ImGui::EndGroup();

```

## Summary

- **Source API**: Wrap widgets with `BeginDragDropSource()` / `EndDragDropSource()` and attach data via `SetDragDropPayload()`.
- **Target API**: Wrap widgets with `BeginDragDropTarget()` / `EndDragDropTarget()` and retrieve data using `AcceptDragDropPayload()`.
- **Payload Types**: Use unique string identifiers (e.g., `"MY_ITEM"`) to filter compatible drag and drop operations.
- **Implementation**: Core logic resides in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (definitions) and [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) (state machine), with [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) handling payload storage.
- **Flags**: Use `ImGuiDragDropFlags_SourceNoPreviewTooltip` to hide default tooltips and `ImGuiCond_Once` to persist payloads after source destruction.

## Frequently Asked Questions

### What is the maximum size of a drag and drop payload?

ImGui does not enforce a hard limit on payload size, but the payload is memcpy'd into an internal buffer managed by the `ImGuiPayload` structure. For large data transfers, store pointers to heap-allocated data rather than copying the data directly, and ensure the pointed-to memory remains valid for the duration of the drag operation.

### Can I drag from a widget that disappears after starting the drag?

Yes. Pass `ImGuiCond_Once` or `ImGuiCond_Always` as the fourth argument to `SetDragDropPayload()`. This keeps the payload alive in the internal drag and drop state even if the source widget is no longer rendered in subsequent frames, which is essential for scrolling lists or toolbars where the source may scroll out of view.

### How do I handle multiple item types in a single drop target?

Call `AcceptDragDropPayload()` multiple times with different type strings, or pass `NULL` as the type to accept any payload. The function returns a pointer to `ImGuiPayload` only if the hovering payload matches the requested type, allowing you to implement different logic for different data types within the same `BeginDragDropTarget()` block.

### Where can I find the official demo implementation?

The official demo is located in [`examples/example_demo.cpp`](https://github.com/ocornut/imgui/blob/main/examples/example_demo.cpp) under the "Widgets -> Drag and Drop" section. This file, part of the `ocornut/imgui` repository, provides comprehensive examples including dragging colors, text, and tree nodes, demonstrating the full capabilities of the API as implemented in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp).