Creating Popup Modals and Context Menus in Dear ImGui: A Complete Guide
Dear ImGui implements popups, modals, and context menus as temporary overlay windows managed by an internal popup stack, using a three-step pattern of triggering with OpenPopup(), beginning with BeginPopup() or BeginPopupModal(), and closing automatically or via CloseCurrentPopup().
When building immediate-mode interfaces with the ocornut/imgui repository, creating popup modals and context menus in ImGui follows a consistent stack-based architecture that differs from traditional window management. Unlike persistent window objects, these elements live only for the duration of the frame loop as temporary overlays, making them lightweight, naturally nestable, and simple to implement.
The Three-Step Popup Lifecycle
Every popup in Dear ImGui follows an identical workflow regardless of whether it is a simple tooltip, a blocking modal dialog, or a right-click context menu. This pattern relies on an internal g.OpenPopupStack that tracks which overlays are currently active.
Step 1: Triggering the Popup
To display a popup, you must first signal Dear ImGui to open it by calling ImGui::OpenPopup() or a helper variant such as ImGui::OpenPopupOnItemClick(). This function pushes an ImGuiPopupData entry onto the global g.OpenPopupStack, storing the popup's identifier, opening position, and frame count. According to the source in imgui.cpp around line 12413, OpenPopupEx performs this stack manipulation.
if (ImGui::Button("Show Options"))
ImGui::OpenPopup("MyPopup"); // Stores ID in g.OpenPopupStack
Step 2: Beginning the Popup Window
Inside your frame loop, call ImGui::BeginPopup() for standard overlays or ImGui::BeginPopupModal() for dialogs that block interaction with the rest of the UI. These functions check g.OpenPopupStack against the current BeginPopupStack and return true only if the popup was actually triggered this frame, allowing you to render contents safely inside the conditional block. The core logic resides in imgui.cpp near line 12653, where BeginPopupEx validates the stack and creates a temporary window with ImGuiWindowFlags_Popup.
if (ImGui::BeginPopup("MyPopup"))
{
// Contents only render when popup is active
ImGui::EndPopup();
}
Step 3: Rendering Content and Handling Closure
Once inside the popup block, add any widgets needed. The overlay closes automatically when the user clicks outside, selects a menu item, or you explicitly call ImGui::CloseCurrentPopup(), which removes the top entry from the stack as implemented in imgui.cpp near line 12575. For modal dialogs, you must also manage a boolean state variable to prevent immediate reopening.
Core Implementation Details
The robustness of Dear ImGui's popup system comes from its centralized stack management in imgui.cpp. Key functions include:
OpenPopupEx(imgui.cpp#L12413‑L12430): Validates the popup ID and appends it tog.OpenPopupStack, handling positioning and focus.BeginPopupEx(imgui.cpp#L12653‑L12663): Compares the requested ID against the open stack and initializes the window withImGuiWindowFlags_PopuporImGuiWindowFlags_Modal.CloseCurrentPopup(imgui.cpp#L12575‑L12592): Pops the topmost entry from the stack, effectively closing the current overlay.
Because popups use string identifiers (or ImGuiID) relative to the current ID stack, you can maintain several independent popups simultaneously without naming collisions, and nesting works naturally when a popup trigger is placed inside another popup's block.
Practical Code Examples
Simple Popup Window (Non-Modal)
This example demonstrates a basic popup triggered by a button, referencing the "Color Picker" implementation in imgui_demo.cpp around line 1255.
if (ImGui::Button("Show Popup"))
ImGui::OpenPopup("MySimplePopup");
if (ImGui::BeginPopup("MySimplePopup"))
{
ImGui::Text("This is a regular popup.");
if (ImGui::Button("Close"))
ImGui::CloseCurrentPopup(); // Optional: clicking elsewhere also closes
ImGui::EndPopup();
}
Modal Dialog Implementation
Modal windows block background interaction until dismissed. This pattern appears in the "Delete?" confirmation dialog in imgui_demo.cpp near line 5554.
static bool show_modal = false;
if (ImGui::Button("Delete…"))
show_modal = true;
if (show_modal)
ImGui::OpenPopup("DeleteConfirm");
if (ImGui::BeginPopupModal("DeleteConfirm", nullptr,
ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("Are you sure you want to delete the item?");
if (ImGui::Button("Yes"))
{
// …perform deletion…
show_modal = false;
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel"))
{
show_modal = false;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
Context Menu on Items
Context menus use helper functions from imgui_widgets.cpp to automatically handle right-click detection. The following pattern appears throughout imgui_demo.cpp near lines 2360 and 5466.
ImGui::Text("Right‑click me");
if (ImGui::BeginPopupContextItem()) // Uses last item's ID as popup identifier
{
if (ImGui::MenuItem("Copy"))
/* …copy logic… */;
if (ImGui::MenuItem("Delete"))
/* …delete logic… */;
ImGui::EndPopup();
}
For window-level context menus (triggered by right-clicking the background), use ImGui::BeginPopupContextWindow() instead.
Summary
- Popups are stack-based: Dear ImGui uses
g.OpenPopupStackto manage overlay state, withOpenPopup()to push andCloseCurrentPopup()to pop. - Three functions define the lifecycle: Trigger with
OpenPopup(), begin rendering withBeginPopup()orBeginPopupModal(), and close implicitly or explicitly. - Identifiers are hierarchical: Popup IDs respect the current ID stack, enabling natural nesting and scoping without global name pollution.
- Reference implementations: Study
imgui_demo.cppfor usage patterns,imgui_widgets.cppfor context menu helpers, andimgui.cppfor the core stack logic.
Frequently Asked Questions
What is the difference between BeginPopup and BeginPopupModal?
BeginPopup creates a standard overlay that allows interaction with the rest of the UI and closes automatically when clicking outside. BeginPopupModal creates a blocking dialog that disables interaction with background windows and requires explicit closure via CloseCurrentPopup() or programmatic state management, as shown in the delete confirmation example in imgui_demo.cpp#L5554‑L5608.
Can I nest popups inside other popups in ImGui?
Yes. Because popup identifiers are resolved relative to the current ID stack, you can call OpenPopup() and BeginPopup() from within another popup's rendering block. Dear ImGui maintains separate entries in g.OpenPopupStack for each level, allowing unlimited nesting depth provided each popup has a unique identifier within its parent's scope.
How do I prevent a popup from closing when the user clicks outside?
Use ImGui::BeginPopupModal() instead of ImGui::BeginPopup(). Modal windows explicitly block background clicks from closing the overlay and remain open until you call CloseCurrentPopup() or manually clear the trigger state. Standard popups created with BeginPopup() always close on outside clicks by design.
What is the difference between BeginPopupContextItem and BeginPopupContextWindow?
BeginPopupContextItem() opens a context menu when right-clicking the last drawn item, automatically using that item's ID as the popup identifier. BeginPopupContextWindow() opens a menu when right-clicking anywhere in the current window's background or empty space. Both helpers are implemented in imgui_widgets.cpp and handle the OpenPopup() call internally.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →