# ImGui Drag and Drop Between Windows Implementation: Complete Guide

> Implement ImGui drag and drop between windows with this complete guide. Learn how ImGui's global context state enables seamless cross-window payload transfers for your applications.

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

---

**Dear ImGui implements cross-window drag and drop through a global context state (`g.DragDropActive`) that persists across all windows in the same `ImGuiContext`, allowing any window to accept payloads from any other window without additional configuration.**

The `ocornut/imgui` repository provides a unified drag-and-drop API that functions identically whether the source and target widgets reside in the same window or different ones. Because the drag state lives in the global context rather than individual windows, implementing **ImGui drag and drop between windows** requires only the standard source-target pattern without window-specific handling.

## How Cross-Window Drag and Drop Works

The drag-and-drop subsystem stores all active state—including the payload buffer, source ID, and target candidates—in the global `ImGuiContext` structure. When you call `ImGui::BeginDragDropSource()` in Window A, the library sets `g.DragDropActive` to true and caches the payload data. Subsequent calls to `ImGui::BeginDragDropTarget()` in Window B query this same global state, validating hover rectangles and payload types against the stored source information.

This architecture means the only requirement for cross-window compatibility is that both windows belong to the same ImGui context. The source and target need not know about each other’s existence; the context mediates all communication automatically.

## Implementing the Drag Source

To initiate a drag operation that can be received by any window, wrap your source widget with `ImGui::BeginDragDropSource()` and `ImGui::EndDragDropSource()`.

### Starting the Drag Operation

Call `ImGui::BeginDragDropSource()` immediately after the item you want to make draggable. According to the source code in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), this function validates the item’s `ImGuiID` and activates the global drag state【link-15016】.

For widgets without unique identifiers—such as `ImGui::Text()` or `ImGui::Image()`—pass the `ImGuiDragDropFlags_SourceAllowNullID` flag to allow dragging from items that would otherwise be ignored by the ID system.

### Setting the Payload

While the source is active, you must call `ImGui::SetDragDropPayload()` exactly once to copy your data into ImGui’s internal buffer:

```cpp
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
    const char* my_data = "Cross-window payload";
    ImGui::SetDragDropPayload("MY_TYPE", my_data, strlen(my_data) + 1);
    ImGui::Text("Dragging: %s", my_data);
    ImGui::EndDragDropSource();
}

```

The `SetDragDropPayload` function, implemented in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), copies the data to a heap or local buffer and records the type string (maximum 32 characters)【link-15150】. The payload remains valid until `ImGui::EndDragDropSource()` is called or a target accepts the data【link-15135】.

### Source Flags

- **`ImGuiDragDropFlags_SourceAllowNullID`**: Enables dragging from widgets without an ID (e.g., text labels or images).
- **`ImGuiDragDropFlags_SourceNoPreviewTooltip`**: Suppresses the default tooltip that follows the cursor during the drag.

## Implementing the Drop Target

Any window can act as a drop target by calling `ImGui::BeginDragDropTarget()` on the item that should receive the payload.

### Declaring the Target

In [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), `BeginDragDropTarget()` checks that the mouse hovers the target item’s rectangle (verified by the `ImGuiItemStatusFlags_HoveredRect` flag) and that the target’s ID differs from the source’s ID. If the target widget lacks an ID, ImGui generates a temporary one from the item’s screen rectangle【link-15264】.

```cpp
if (ImGui::BeginDragDropTarget()) {
    // Target is active and accepting payloads
    ImGui::EndDragDropTarget();
}

```

### Accepting the Payload

Use `ImGui::AcceptDragDropPayload()` to validate the payload type and retrieve the data pointer:

```cpp
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_TYPE")) {
    const char* received_data = (const char*)payload->Data;
    // Process data
}

```

This function, located in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), validates the type string, registers the acceptance with the global context, and draws a default drop rectangle highlight unless you specify `ImGuiDragDropFlags_AcceptNoDrawDefaultRect`【link-15308】. After `ImGui::EndDragDropTarget()` returns, the payload is cleared from the global state if it was delivered【link-15364】.

## Complete Cross-Window Example

The following implementation demonstrates dragging a string payload from "Source Window" to "Target Window" using the global context:

```cpp
// Source Window
if (ImGui::Begin("Source Window")) {
    ImGui::Button("Drag Me");
    
    if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
        const char* payload_str = "Hello from Window A";
        ImGui::SetDragDropPayload("STRING_PAYLOAD", payload_str, strlen(payload_str) + 1);
        ImGui::Text("Dragging to another window...");
        ImGui::EndDragDropSource();
    }
    ImGui::End();
}

// Target Window
if (ImGui::Begin("Target Window")) {
    ImGui::Text("Drop payload here:");
    
    if (ImGui::BeginDragDropTarget()) {
        if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("STRING_PAYLOAD")) {
            IM_ASSERT(payload->DataSize == strlen((const char*)payload->Data) + 1);
            ImGui::Text("Received: %s", (const char*)payload->Data);
        }
        ImGui::EndDragDropTarget();
    }
    ImGui::End();
}

```

This example appears in various forms in [`imgui_demo.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_demo.cpp), where multiple demo windows showcase dragging colors and text between separate windows【link-demo-1689】.

## Key Configuration Flags

Control visual feedback and validation behavior using these flags from [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h):

| Flag | Effect |
|------|--------|
| `ImGuiDragDropFlags_SourceAllowNullID` | Allows dragging from widgets without identifiers (e.g., `Text()`, `Image()`). |
| `ImGuiDragDropFlags_SourceNoPreviewTooltip` | Hides the default preview tooltip during the drag operation. |
| `ImGuiDragDropFlags_SourceNoHoldToOpenOthers` | Prevents holding the drag from opening tree nodes or collapsing headers. |
| `ImGuiDragDropFlags_AcceptNoDrawDefaultRect` | Prevents ImGui from drawing the default rectangle around the target. |
| `ImGuiDragDropFlags_AcceptNoPreviewTooltip` | Suppresses the source’s preview tooltip when hovering this specific target. |
| `ImGuiDragDropFlags_AcceptPeekOnly` | Allows peeking at the payload without consuming it (returns payload but does not mark as delivered). |

## Summary

- **Global State**: Drag-and-drop data lives in `ImGuiContext` (`g.DragDropActive`, `g.DragDropPayload`), making cross-window transfers automatic.
- **Source Pattern**: Call `BeginDragDropSource()`, `SetDragDropPayload()`, and `EndDragDropSource()` on the draggable widget.
- **Target Pattern**: Call `BeginDragDropTarget()`, `AcceptDragDropPayload()`, and `EndDragDropTarget()` on the receiving widget.
- **No Window References**: The API never requires passing window pointers; the context handles routing between any windows in the same context.
- **Reference Implementation**: See [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) for the core logic and [`imgui_demo.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_demo.cpp) for working examples of multi-window drag operations.

## Frequently Asked Questions

### Does ImGui drag and drop require special setup for multiple windows?

No. The drag-and-drop system operates entirely through the global `ImGuiContext`. As long as both windows are rendered within the same context (the default behavior), payloads automatically transfer between them without additional configuration or window handles.

### What happens if the target window is behind the source window?

The payload remains active as long as the mouse button is held. If the target window is behind the source, standard ImGui window focus behavior applies—clicking or dragging over the target window will bring it to the front (depending on your window focus settings), and the drop will register normally if the hover test succeeds.

### Can I drag from a widget that doesn't have an ID?

Yes. Pass the `ImGuiDragDropFlags_SourceAllowNullID` flag to `BeginDragDropSource()`. This is necessary for widgets like `ImGui::Text()` or `ImGui::Image()` that do not generate unique identifiers automatically. Without this flag, `BeginDragDropSource()` returns false for ID-less items【link-15016】.

### How long does the payload data remain valid?

The payload persists until either the source calls `EndDragDropSource()` or the target calls `EndDragDropTarget()` after accepting the payload. Internally, ImGui copies your data to an internal buffer during `SetDragDropPayload()`, so the original pointer need not remain valid after the call【link-15150】.