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

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:

  • 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) 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). 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 and 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 (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:

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:

#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:

// 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:

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

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 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →