# How to Implement Multi-Viewport Support to Render Dear ImGui Windows on Multiple Monitors

> Learn to implement multi-viewport support for Dear ImGui, rendering windows across multiple monitors. Enable viewports, update your backend, and call essential ImGui functions each frame.

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

---

**Enable `ImGuiConfigFlags_ViewportsEnable` in your `ImGuiIO` configuration, ensure your backend implements the viewport API, and call `ImGui::UpdatePlatformWindows()` followed by `ImGui::RenderPlatformWindowsDefault()` after `ImGui::Render()` each frame to render UI windows on multiple monitors.**

Dear ImGui's **multi-viewport support** allows you to drag windows outside the main application frame onto separate monitors, with each viewport rendering as a native platform window. This feature is built into the core library but requires specific configuration flags and backend support according to the ocornut/imgui source code. Below is the complete implementation guide based on the actual codebase.

## Enabling the Viewport Configuration Flag

To activate multi-viewport functionality, you must set the configuration flag before the first frame. The flag is defined in **[`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)** within the `ImGuiConfigFlags_` enum at lines 1728-1734.

```cpp
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;   // enable multi-viewport

```

**Critical:** Set this flag **before** calling `ImGui::NewFrame()` for the first time. If enabled afterward, the main viewport will not be correctly marked as a platform window, causing initialization failures.

## Backend Requirements for Platform Windows

Multi-viewport support requires a backend that implements the **Platform Window API**. Official backends such as GLFW ([`imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_glfw.cpp)), SDL2 ([`imgui_impl_sdl2.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_sdl2.cpp)), and Win32 ([`imgui_impl_win32.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_win32.cpp)) provide this implementation.

According to the GLFW backend source, the function `ImGui_ImplGlfw_CreateWindow()` in **[`backends/imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_glfw.cpp)** handles the creation of native windows for secondary viewports. The backend must:

- Create a native window handle (e.g., `GLFWwindow*`) when ImGui requests a new viewport
- Store the handle in `ImGuiViewport::PlatformHandleRaw`
- Implement destruction via the corresponding `DestroyWindow` function

Verify your backend contains viewport-specific functions; otherwise, the system will silently fall back to single-window mode.

## Main Loop Integration

After rendering the main viewport, you must explicitly update and render secondary viewports. The core library marks the main viewport as a platform window in **[`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)** at line 16120, setting the flags `ImGuiViewportFlags_IsPlatformWindow` and `ImGuiViewportFlags_OwnedByApp`.

Add these calls after `ImGui::Render()`:

```cpp
ImGui::Render();                              // render main viewport
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
    ImGui::UpdatePlatformWindows();           // create/update secondary viewports
    ImGui::RenderPlatformWindowsDefault();    // render all platform windows
}

```

`UpdatePlatformWindows()` synchronizes viewport geometry and creates new platform windows when you drag ImGui windows to new monitors. `RenderPlatformWindowsDefault()` iterates through the `ImGuiContext::Viewports` vector and renders each viewport's `ImDrawData`.

## Understanding the Viewport Architecture

The viewport system uses several key structures defined in the ImGui headers:

| Component | Source Location | Purpose |
|-----------|----------------|---------|
| **`ImGuiViewport`** | [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 4017-4045) | Represents a platform window with size, position, DPI scale, and platform handles |
| **`ImGuiContext::Viewports`** | [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) (lines 2379-2381) | Vector storing all active viewports (`ImVector<ImGuiViewport*>`) |
| **`ImGuiWindow::Viewport`** | [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) | Pointer linking each ImGui window to its host viewport |
| **Platform Interface** | Backend files (e.g., [`imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_glfw.cpp)) | Functions creating native OS windows for each viewport |

When you drag a window to a new monitor, ImGui detects the monitor change, creates a new `ImGuiViewport` entry, and requests the backend to create a corresponding native window via the platform interface.

## DPI Scaling and Multi-Monitor Considerations

Each viewport maintains its own DPI scale factor. Access this via `ImGui::GetWindowViewport()->DpiScale` or `viewport->DpiScale` to ensure UI elements scale correctly on high-DPI monitors.

Common implementation pitfalls to avoid:

- **Flag initialization order:** Always set `ImGuiConfigFlags_ViewportsEnable` before the first `NewFrame()` call
- **Missing backend support:** Custom backends must implement the full viewport interface (create, destroy, show, set position/size)
- **Event forwarding:** Ensure your platform's event loop forwards input events (mouse, keyboard, focus) to all viewport windows, not just the main window

## Complete Implementation Example (GLFW + OpenGL3)

Below is a minimal working example using the official GLFW and OpenGL3 backends. The same pattern applies to SDL, Vulkan, DirectX, and other supported backends.

```cpp
// Setup
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;   // enable multi-viewport

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

// Main loop
while (!glfwWindowShouldClose(window)) {
    glfwPollEvents();
    
    ImGui_ImplGlfw_NewFrame();
    ImGui_ImplOpenGL3_NewFrame();
    ImGui::NewFrame();

    // UI code
    ImGui::Begin("Main Window");
    ImGui::Text("Drag this window to another monitor");
    ImGui::End();

    ImGui::Begin("Secondary Window");
    ImGui::Text("This renders on its own platform window");
    ImGui::End();

    // Rendering
    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());

    // Multi-viewport handling
    if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
        ImGui::UpdatePlatformWindows();
        ImGui::RenderPlatformWindowsDefault();
    }

    glfwSwapBuffers(window);
}

```

## Summary

- **Enable the global flag:** Set `ImGuiConfigFlags_ViewportsEnable` in your `ImGuiIO` struct before the first frame
- **Use a compatible backend:** Verify your platform backend implements `CreateWindow`, `DestroyWindow`, and other viewport functions (official GLFW, SDL, and Win32 backends support this)
- **Update the render loop:** Call `ImGui::UpdatePlatformWindows()` and `ImGui::RenderPlatformWindowsDefault()` after `ImGui::Render()` to handle secondary viewports
- **Handle DPI per viewport:** Query `viewport->DpiScale` for monitor-specific scaling instead of using a global scale factor
- **Reference key files:** The feature implementation spans [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (definitions), [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) (viewport flags at line 16120), and [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h) (viewport vector storage)

## Frequently Asked Questions

### Why do my windows still appear inside the main application window?

You likely set `ImGuiConfigFlags_ViewportsEnable` after calling `ImGui::NewFrame()` for the first time. The flag must be enabled during ImGui initialization, before the first frame begins. Additionally, verify that your backend implements the viewport API functions; if using an older custom backend that lacks these functions, multi-viewport support will silently fail.

### Do I need to manually create native windows for each monitor?

No. When you enable the viewport flag and use a supporting backend, Dear ImGui automatically creates and manages native platform windows (via the backend) when you drag ImGui windows outside the main viewport. The `ImGui::UpdatePlatformWindows()` function handles the lifecycle of these native windows based on viewport visibility.

### How do I handle different DPI scales across multiple monitors?

Each `ImGuiViewport` stores its own `DpiScale` factor. Query this value via `ImGui::GetWindowViewport()->DpiScale` or iterate through the viewport list to adjust font sizes or spacing per monitor. The backend typically sets this value when the viewport moves to a monitor with different DPI settings.

### Can I use multi-viewport with Vulkan or DirectX instead of OpenGL?

Yes. Multi-viewport support is backend-agnostic regarding the graphics API. You can use it with the official Vulkan ([`imgui_impl_vulkan.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_vulkan.cpp)), DirectX 11 ([`imgui_impl_dx11.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_dx11.cpp)), or DirectX 12 backends. The requirement is that the **platform backend** (GLFW, SDL, or Win32) implements the window management interface, while the renderer backend handles the draw calls for each viewport's `ImDrawData`.