# How to Implement Multi-Window and Multi-Viewport in Dear ImGui

> Unlock ImGui multi window and multi viewport capabilities. Learn how to enable viewports easily with simple configuration flags and backend setup for a better UI experience.

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

---

**To enable multi-viewport support in Dear ImGui, set `io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable`, ensure your backend supports `ImGuiBackendFlags_PlatformHasViewports`, and call `ImGui::UpdatePlatformWindows()` followed by `ImGui::RenderPlatformWindowsDefault()` after your main render loop.**

Dear ImGui (ocornut/imgui) can render **multiple OS-level windows**—called *viewports*—from a single ImGui context. This feature allows users to drag ImGui windows outside the main application boundary, creating native platform windows dynamically. Implementing multi-window and multi-viewport in ImGui requires specific configuration flags, backend support, and explicit rendering steps in your application loop.

## Understanding the Multi-Viewport Architecture

### Core Components and Configuration

The multi-viewport system relies on three primary structures defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h):

- **`ImGuiIO::ConfigFlags`** – Setting `ImGuiConfigFlags_ViewportsEnable` (declared around lines 213–218) activates the feature at runtime. Without this flag, ImGui operates in single-window mode regardless of backend capabilities.

- **`ImGuiViewport`** – This struct (defined at lines 4017–4038 in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)) represents a platform window. It stores size, position, DPI scale, and the platform-specific handle (`PlatformHandle`) such as an `HWND` on Windows or `GLFWwindow*` on GLFW.

- **`ImGuiBackendFlags`** – Backends signal viewport support through `ImGuiBackendFlags_PlatformHasViewports` and optionally `ImGuiBackendFlags_RendererHasViewports` (lines 4420–4425 in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)). The platform backend creates and manages native windows, while the renderer backend handles the GPU resources for each viewport.

### Platform Backend Responsibilities

Platform-specific code lives entirely within the backends. Files like [`backends/imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_glfw.cpp) and [`backends/imgui_impl_win32.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_win32.cpp) implement the required platform-window callbacks:

- Creating native windows when a viewport is spawned
- Updating window position, size, and DPI scale
- Forwarding mouse and keyboard events to the correct viewport

This decoupling ensures ImGui core never touches graphics APIs or OS window systems directly.

### The Rendering Lifecycle with Viewports

When viewports are enabled, the render loop expands beyond the standard `ImGui::Render()` call. According to the implementation in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) (lines 7756–7770), the lifecycle becomes:

1. **Update** – `ImGui::UpdatePlatformWindows()` creates or updates extra OS windows
2. **Render** – `ImGui::RenderPlatformWindowsDefault()` generates draw data for each viewport
3. **Present** – Each viewport's draw data is submitted to the GPU

## Implementation Guide

### Enabling Viewport Support

Activate the feature immediately after creating the ImGui context:

```cpp
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;

```

Without this flag, the viewport functions exist but remain inactive, and all windows render within the main application window.

### Complete GLFW and OpenGL3 Example

This minimal implementation demonstrates the full integration:

```cpp
#include "imgui.h"
#include "backends/imgui_impl_glfw.h"
#include "backends/imgui_impl_opengl3.h"
#include <GLFW/glfw3.h>

int main()
{
    // Initialize GLFW and create main window
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui Viewports", nullptr, nullptr);
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    // Create ImGui context and enable viewports
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();
    io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;

    // Initialize backends
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init("#version 130");

    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();

        // Start frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();

        // UI code - windows can be dragged out to become OS windows
        ImGui::Begin("Demo Window");
        ImGui::Text("Drag this title bar outside the main window");
        ImGui::End();

        // Render main viewport
        ImGui::Render();
        int display_w, display_h;
        glfwGetFramebufferSize(window, &display_w, &display_h);
        glViewport(0, 0, display_w, display_h);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        // Handle additional viewports
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
        }

        glfwSwapBuffers(window);
    }

    // Cleanup
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();
    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

```

The critical additions are `UpdatePlatformWindows()` and `RenderPlatformWindowsDefault()` after the standard render call. The same OpenGL3 backend handles all viewports automatically—no additional renderer code is required.

### Custom Backend Integration

If implementing a custom platform or renderer (such as for WGPU or a proprietary engine), you must provide callback functions through `ImGuiPlatformIO`:

```cpp
// Platform callbacks
void MyPlatform_CreateWindow(ImGuiViewport* vp);
void MyPlatform_DestroyWindow(ImGuiViewport* vp);
void MyPlatform_SetWindowPos(ImGuiViewport* vp, ImVec2 pos);
void MyPlatform_GetWindowPos(ImGuiViewport* vp, ImVec2* out_pos);
void MyPlatform_SetWindowSize(ImGuiViewport* vp, ImVec2 size);

// Renderer callback
void MyPlatform_RenderWindow(ImGuiViewport* vp, ImDrawData* draw_data);

```

Register these callbacks after initializing your backend:

```cpp
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Platform_CreateWindow = MyPlatform_CreateWindow;
platform_io.Platform_DestroyWindow = MyPlatform_DestroyWindow;
platform_io.Platform_SetWindowPos = MyPlatform_SetWindowPos;
platform_io.Platform_GetWindowPos = MyPlatform_GetWindowPos;
platform_io.Platform_SetWindowSize = MyPlatform_SetWindowSize;
platform_io.Platform_RenderWindow   = MyPlatform_RenderWindow;

```

Once registered, `ImGui::UpdatePlatformWindows()` and `ImGui::RenderPlatformWindowsDefault()` will invoke your implementations for each active viewport.

## Key Source Files and References

- **[`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)** – Contains `ImGuiViewport` definition, `ImGuiConfigFlags_ViewportsEnable`, and `ImGuiBackendFlags` enum
- **[`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)** – Implements `UpdatePlatformWindows()` and `RenderPlatformWindowsDefault()` around lines 7756–7770
- **[`backends/imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_glfw.cpp)** – GLFW platform implementation creating native `GLFWwindow*` objects for viewports
- **[`backends/imgui_impl_win32.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_win32.cpp)** – Windows platform implementation using `HWND` for viewport windows
- **[`backends/imgui_impl_opengl3.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_opengl3.cpp)** – OpenGL renderer supporting multiple viewport framebuffers
- **[`examples/example_glfw_opengl3/main.cpp`](https://github.com/ocornut/imgui/blob/main/examples/example_glfw_opengl3/main.cpp)** – Reference implementation showing viewports in practice
- **[`docs/BACKENDS.md`](https://github.com/ocornut/imgui/blob/main/docs/BACKENDS.md)** – Official documentation listing which backends support the multi-viewport feature

## Summary

- **Enable viewports** by setting `io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable` immediately after creating the context
- **Verify backend support** – Your platform backend must set `ImGuiBackendFlags_PlatformHasViewports` in `io.BackendFlags`
- **Add viewport rendering** – Call `ImGui::UpdatePlatformWindows()` and `ImGui::RenderPlatformWindowsDefault()` after your main `Render()` call
- **Handle DPI scaling** – Each `ImGuiViewport` stores its own `Scale` field; query `ImGui::GetMainViewport()->WorkPos` for positioning
- **Test by dragging** – Any ImGui window can become a separate OS window by dragging its title bar outside the main window bounds

## Frequently Asked Questions

### What backends support multi-viewport in Dear ImGui?

The official GLFW, Win32, and SDL2 platform backends support multi-viewport when `ImGuiBackendFlags_PlatformHasViewports` is set. The OpenGL3, DirectX 11/12, and Vulkan renderers support multi-viewport rendering. Check [`docs/BACKENDS.md`](https://github.com/ocornut/imgui/blob/main/docs/BACKENDS.md) in the repository for the current support matrix, as third-party backends vary in viewport capability.

### Why won't my ImGui window detach into a separate OS window?

First, verify that `io.ConfigFlags` includes `ImGuiConfigFlags_ViewportsEnable` before calling `NewFrame()`. Second, confirm your backend sets `ImGuiBackendFlags_PlatformHasViewports` during initialization. Finally, ensure you are calling both `ImGui::UpdatePlatformWindows()` and `ImGui::RenderPlatformWindowsDefault()` in your render loop—missing either prevents viewport creation or rendering.

### Can I implement multi-viewport with a custom game engine renderer?

Yes, but you must implement the `ImGuiPlatformIO` callbacks. Your platform layer needs to create and destroy native windows, handle window movement and resizing, and forward input events. Your renderer must output to the correct framebuffer or swapchain for each viewport's `PlatformHandle`. Reference [`imgui_impl_win32.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_win32.cpp) for a complete implementation pattern.

### Does multi-viewport work with docking enabled?

Yes. The docking branch (and later merged versions) integrates seamlessly with multi-viewport. When both features are enabled, docked windows remain within their containing viewport, while dragging a window tab outside any viewport boundary automatically creates a new OS-level window. The `ImGuiViewport` struct tracks the parent-child relationships through the `ParentViewportId` field.