# How to Implement Drag and Drop Functionality Between Widgets Using ImGuiPayload

> Implement drag and drop functionality between widgets in ImGui using ImGuiPayload. Learn to initiate drags, set payloads, and accept them on target widgets for seamless UI interactions.

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

---

**Use `ImGui::BeginDragDropSource()` to initiate dragging from a widget, attach data with `ImGui::SetDragDropPayload()`, then call `ImGui::BeginDragDropTarget()` on destination widgets and retrieve the payload using `ImGui::AcceptDragDropPayload()` to enable drag-and-drop interactions in Dear ImGui.**

Dear ImGui (ocornut/imgui) provides a lightweight, immediate-mode drag-and-drop system built around the `ImGuiPayload` structure. By wrapping your widget rendering code with specific API calls defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h), you can implement drag and drop functionality between widgets using ImGuiPayload without maintaining complex state machines. This guide demonstrates the complete pipeline with production-ready code patterns drawn directly from the source.

## Core Architecture of ImGui Drag-and-Drop

The system revolves around three distinct roles working together statelessly:

- **Drag Source**: The widget initiating the drag operation
- **Payload**: The `ImGuiPayload` structure containing user-defined data and type identifiers  
- **Drop Target**: The widget accepting the payload

According to the source code in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (around line 976), the API is deliberately non-intrusive—you wrap existing widget code rather than inheriting from specialized classes. The payload lives only while the source is active or until the user releases the mouse, making the system trivial to integrate with any widget.

## Implementing the Drag Source

To make any widget draggable, wrap its rendering code with `BeginDragDropSource()` and `EndDragDropSource()`.

### Starting the Drag Operation

Call `ImGui::BeginDragDropSource()` immediately after submitting the widget item. This function returns `true` only when the user is actively dragging the item with the mouse button held:

```cpp
if (ImGui::Selectable("Draggable Item")) { /* selection logic */ }
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
    // Drag operation is active
    ImGui::EndDragDropSource();
}

```

### Attaching the Payload

Use `ImGui::SetDragDropPayload()` to attach data to the drag operation. The `type` parameter is a null-terminated string identifier (e.g., `"MY_ITEM"`), and the `cond` parameter controls payload persistence:

```cpp
int item_id = 42;
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
    ImGui::SetDragDropPayload("MY_ITEM", &item_id, sizeof(item_id), ImGuiCond_Always);
    ImGui::Text("Dragging Item %d", item_id);
    ImGui::EndDragDropSource();
}

```

Passing `ImGuiCond_Always` ensures the payload remains available even if the source widget disappears during the drag operation, which is essential for dragging from scrolling lists or transient toolbars.

## Configuring the Drop Target

### Detecting Compatible Payloads

Call `ImGui::BeginDragDropTarget()` after submitting the target widget. This function returns `true` when a compatible payload hovers over the item:

```cpp
ImGui::Button("Drop Zone");
if (ImGui::BeginDragDropTarget()) {
    // Payload is hovering over this button
    ImGui::EndDragDropTarget();
}

```

### Accepting and Processing the Payload

Retrieve the `ImGuiPayload` pointer using `ImGui::AcceptDragDropPayload()`. Always verify the `DataSize` field matches your expected structure before casting the `Data` pointer:

```cpp
if (ImGui::BeginDragDropTarget()) {
    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_ITEM")) {
        IM_ASSERT(payload->DataSize == sizeof(int));
        int received_id = *static_cast<const int*>(payload->Data);
        OnItemDropped(received_id);
    }
    ImGui::EndDragDropTarget();
}

```

The `ImGuiPayload` structure (defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 199) contains the `Data` and `DataSize` fields pointing to an internal buffer managed by the drag-and-drop state machine in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp).

## Complete Working Example

Here is a complete implementation demonstrating drag-and-drop between a list item and a drop zone, following the pattern found in [`examples/example_demo.cpp`](https://github.com/ocornut/imgui/blob/main/examples/example_demo.cpp):

```cpp
// Drag source implementation
if (ImGui::Selectable(item_label)) { /* handle selection */ }
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
    ImGui::SetDragDropPayload("MY_ITEM", &item_id, sizeof(item_id));
    ImGui::Text("Dragging %s", item_label);
    ImGui::EndDragDropSource();
}

// Drop target implementation  
ImGui::Button("Drop Here");
if (ImGui::BeginDragDropTarget()) {
    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_ITEM")) {
        IM_ASSERT(payload->DataSize == sizeof(int));
        int received_id = *static_cast<const int*>(payload->Data);
        OnItemDropped(received_id);
    }
    ImGui::EndDragDropTarget();
}

```

## Advanced Configuration Options

### Controlling Tooltip Visibility

Use specific flags to customize preview behavior during drag operations:

- **`ImGuiDragDropFlags_SourceNoPreviewTooltip`**: Hides the default "..." tooltip on the source side
- **`ImGuiDragDropFlags_AcceptNoPreviewTooltip`**: Hides the source tooltip when hovering over the target

### Preview Before Delivery

Enable `ImGuiDragDropFlags_AcceptBeforeDelivery` to receive the payload while the mouse button is still held, allowing you to render "drag-over" previews before the user releases:

```cpp
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_ITEM", 
    ImGuiDragDropFlags_AcceptBeforeDelivery)) {
    // Show preview while dragging without finalizing the drop
}

```

### Supporting Multiple Payload Types

You can call `SetDragDropPayload()` multiple times with different type strings during a single drag operation to offer different data formats. The target can then accept any compatible type it recognizes by calling `AcceptDragDropPayload()` with the appropriate type identifier.

## Summary

- Wrap source widgets with `BeginDragDropSource()` and `EndDragDropSource()` defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (line 976)
- Attach data using `SetDragDropPayload()` with a unique type string and `ImGuiCond_Always` for cross-widget persistence
- Wrap target widgets with `BeginDragDropTarget()` and retrieve data via `AcceptDragDropPayload()`
- Always verify `payload->DataSize` matches your expected structure before casting the `Data` pointer
- Reference the complete implementation in [`examples/example_demo.cpp`](https://github.com/ocornut/imgui/blob/main/examples/example_demo.cpp) under the Demo Window's Drag & Drop section

## Frequently Asked Questions

### Is the ImGuiPayload data copied or referenced?

Dear ImGui copies the payload data into an internal buffer managed by the drag-and-drop state machine in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp). The `ImGuiPayload` structure (defined around line 199 in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)) provides `Data` and `DataSize` fields pointing to this internal copy, ensuring the data remains valid even if the source widget is destroyed during the drag operation.

### Can I drag and drop between different window contexts?

Yes. The drag-and-drop system is global within the ImGui context. As long as both the source and target are rendered within the same `ImGui::NewFrame()` scope, the payload persists across window boundaries. The system stores the payload in the internal `ImGuiContext` structure, making it accessible anywhere in the frame.

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

Call `AcceptDragDropPayload()` with different type strings for each supported format. Check the return value to determine which type was dropped and handle accordingly:

```cpp
if (const ImGuiPayload* p = ImGui::AcceptDragDropPayload("FILE_PATH")) {
    HandleFile(p);
} else if (const ImGuiPayload* p = ImGui::AcceptDragDropPayload("TEXT")) {
    HandleText(p);
}

```

### Why does my payload disappear when the source widget scrolls out of view?

By default, the payload lifetime is tied to the source widget's existence. Pass `ImGuiCond_Always` as the fourth parameter to `SetDragDropPayload()` to keep the payload alive regardless of the source widget's visibility state. This is essential for drag operations originating from scrolling lists, collapsing headers, or transient UI elements.