How to Create Popups, Modals, and Context Menus in Dear ImGui
Dear ImGui creates popups, modals, and context menus using a three-step pattern where you trigger the overlay with ImGui::OpenPopup(), begin it with ImGui::BeginPopup() or ImGui::BeginPopupModal(), and render content inside a conditional block that automatically closes when the user clicks outside or you call ImGui::CloseCurrentPopup().
Dear ImGui (ocornut/imgui) implements these UI elements as temporary overlay windows managed by an internal popup stack. To create popups, modals, and context menus in ImGui, you follow a consistent workflow defined in imgui.cpp that relies on unique identifiers and stack-based state management. This approach allows multiple independent popups to coexist while supporting natural nesting through the ID stack.
The Three-Step Popup Lifecycle
Every popup in Dear ImGui follows the same execution pattern, implemented in imgui.cpp (lines 12413-12430 for OpenPopupEx and 12653-12663 for BeginPopup):
- Trigger the popup – Call
ImGui::OpenPopup()to push aImGuiPopupDataentry ontog.OpenPopupStack. This stores the popup ID, opening position, and frame count. You can also use helpers likeImGui::OpenPopupOnItemClick()orImGui::BeginPopupContextItem()to trigger automatically on user interaction. - Begin the popup – Call
ImGui::BeginPopup()for regular popups,ImGui::BeginPopupModal()for modal dialogs, orImGui::BeginPopupContextItem()for context menus. These functions returntrueonly when the popup is actually opened, allowing you to safely render contents inside the conditional block. - Render content and close – Add any ImGui widgets inside the block. The popup closes automatically when the user clicks outside, selects a menu item, or you explicitly call
ImGui::CloseCurrentPopup()(implemented inimgui.cpp, lines 12575-12592).
Creating a Simple Popup
A standard popup appears when triggered and closes when clicking outside. According to the demo code in imgui_demo.cpp (lines 1250-1259), you can implement a button-triggered popup like this:
// Trigger
if (ImGui::Button("Show Popup"))
ImGui::OpenPopup("MySimplePopup");
// Render content only when open
if (ImGui::BeginPopup("MySimplePopup"))
{
ImGui::Text("This is a regular popup.");
if (ImGui::Button("Close"))
ImGui::CloseCurrentPopup(); // Optional manual close
ImGui::EndPopup();
}
The identifier "MySimplePopup" is hashed into an ImGuiID and checked against g.OpenPopupStack each frame. Because identifiers are relative to the current ID stack, nesting popups inside other UI elements works naturally.
Building a Modal Dialog
Modal windows block interaction with the rest of the UI until dismissed. The implementation in imgui_demo.cpp (lines 5554-5608) demonstrates a confirmation dialog pattern:
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 logic here
show_modal = false;
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel"))
{
show_modal = false;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
Unlike regular popups, BeginPopupModal() creates a window with ImGuiWindowFlags_Modal that darkens the background and prevents clicking through to other windows.
Implementing Context Menus
Context menus open when right-clicking specific items or window space. The helper functions in imgui_widgets.cpp wrap the three-step pattern into convenient calls. As shown in imgui_demo.cpp (lines 2360 and 5466-5485) and imgui_tables.cpp (lines 3661-3670):
ImGui::Text("Right-click me");
if (ImGui::BeginPopupContextItem()) // Uses last item's ID automatically
{
if (ImGui::MenuItem("Copy"))
/* copy logic */;
if (ImGui::MenuItem("Delete"))
/* delete logic */;
ImGui::EndPopup();
}
BeginPopupContextItem() combines the trigger check and begin step, opening the popup when you right-click the preceding item. For window-level context menus, use BeginPopupContextWindow() instead.
Understanding the Popup Stack
The underlying architecture relies on two stacks in imgui.cpp: g.OpenPopupStack (popups waiting to be opened) and g.BeginPopupStack (currently active popups). When you call OpenPopup(), the system pushes an ImGuiPopupData entry containing the ID and desired position. During the next frame, BeginPopup() checks if your ID matches the top of the open stack before creating the temporary window with ImGuiWindowFlags_Popup.
This stack-based design means:
- You can have several independent popups active simultaneously
- Popups automatically handle their own lifecycle management
- Nesting works naturally because each popup maintains its own ID scope
Summary
- Dear ImGui implements popups as temporary overlay windows managed through an internal stack in
imgui.cpp. - Always use three steps: trigger with
OpenPopup(), begin withBeginPopup()/BeginPopupModal(), and render inside the conditional block. - Modal dialogs block background interaction and require explicit closing via
CloseCurrentPopup()or button actions. - Context menus use helpers like
BeginPopupContextItem()that automatically handle right-click detection and identifier management. - Identifiers are relative to the ID stack, allowing natural nesting of popups within other UI elements.
Frequently Asked Questions
What's the difference between a popup and a modal in ImGui?
A regular popup created with ImGui::BeginPopup() allows interaction with the rest of the application while open, and closes automatically when clicking outside. A modal dialog created with ImGui::BeginPopupModal() displays a dimming overlay that blocks interaction with other windows until explicitly closed. Modals also typically use the ImGuiWindowFlags_AlwaysAutoResize flag to fit their content.
How do I close a popup programmatically?
Call ImGui::CloseCurrentPopup() (defined in imgui.cpp, lines 12575-12592) inside the popup's begin/end block. This removes the top entry from the internal popup stack. Alternatively, popups close automatically when the user activates a menu item (via MenuItem() or Selectable()) or clicks outside the window area for non-modal popups.
Can I nest popups inside other popups?
Yes. Because Dear ImGui identifies popups using IDs relative to the current ID stack, you can open a child popup from within a parent popup's begin/end block. Each popup maintains its own entry in g.BeginPopupStack, and the system handles the layering automatically. The table context menu example in imgui_tables.cpp (lines 3661-3670) demonstrates this pattern.
Why does my popup close immediately after opening?
This usually happens when you call OpenPopup() outside the condition that checks for the trigger event, causing it to be called every frame. Ensure you only call OpenPopup() when a specific event occurs (button click, right-click, etc.), and place the BeginPopup() check immediately afterward in the same frame. The popup stack resets each frame, so you must trigger and begin the popup within the same pass.
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 →