How to Create Popup Modals, Context Menus, and Tooltips in Dear ImGui

Dear ImGui implements popups, modals, context menus, and tooltips as lightweight window instances that share a common three-stage lifecycle: open the window with an Open* function, begin it with a Begin* call, and finalize it with a matching End* function.

Dear ImGui (ocornut/imgui) treats every transient overlay—from simple hover hints to blocking dialog boxes—as a specialized window. To create popup modals, context menus, and tooltips in Dear ImGui, you manipulate the global window stack through a consistent API surface declared in imgui.h and implemented in imgui.cpp.

The Three-Stage Popup Lifecycle

Every popup in Dear ImGui follows the same orchestration pattern managed via the internal ImGuiContext::OpenPopupStack and BeginPopupStack (declared in imgui_internal.h). Understanding these three stages is essential before implementing any specific variant.

Stage 1: Opening the Popup

First, request the popup to open using OpenPopup or OpenPopupOnItemClick. These functions (found in imgui.h around lines 861-864) push a marker onto the global g.OpenPopupStack within the current ImGuiContext. The request is processed later in the same frame, but the window does not exist yet.

if (ImGui::Button("Open Settings")) {
    ImGui::OpenPopup("SettingsModal");
}

Stage 2: Beginning the Window

On the subsequent frame—or immediately if the request succeeds—call a begin function such as BeginPopup, BeginPopupModal, or BeginTooltip (declared in imgui.h lines 824-826 and 848-850). These return true only while the popup is actually open, allowing you to emit contents inside the block.

if (ImGui::BeginPopupModal("SettingsModal", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
    // Window is open; draw contents here
}

Stage 3: Ending the Window

Always call the matching EndPopup or EndTooltip (lines 850-852 in imgui.h) to pop the window from the stack and restore the previous window state. ImGui internally cleans up focus and navigation state.

    ImGui::EndPopup(); // Matches BeginPopupModal
}

Creating Modal Popups

Modal popups block interaction with all other windows until closed. Use BeginPopupModal instead of BeginPopup. Internally, this applies the ImGuiWindowFlags_Modal flag (defined in imgui.h line 1201), which directs the library to consume all inputs outside the window boundaries.

The function accepts an optional bool* p_open pointer. Setting this to false (or calling CloseCurrentPopup()) closes the modal.

if (ImGui::Button("Delete File")) {
    ImGui::OpenPopup("ConfirmDelete");
}

bool open = true;
if (ImGui::BeginPopupModal("ConfirmDelete", &open, ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::Text("Are you sure you want to delete?");
    if (ImGui::Button("Yes")) {
        // Perform deletion
        ImGui::CloseCurrentPopup(); // Closes the modal
    }
    ImGui::SameLine();
    if (ImGui::Button("Cancel")) {
        ImGui::CloseCurrentPopup();
    }
    ImGui::EndPopup();
}

Implementing Context Menus

Context menus are popups triggered by user interactions, typically right-clicks. Dear ImGui provides three high-level helpers (in imgui.h lines 875-878) that combine the open and begin steps:

  • BeginPopupContextItem: Opens when the last drawn item is right-clicked.
  • BeginPopupContextWindow: Opens when the background of the current window is right-clicked.
  • BeginPopupContextVoid: Opens when clicking empty space (no windows).

Internally, these use BeginPopupEx with specific ImGuiPopupFlags to test hover states before opening.

ImGui::Selectable("Document.txt");
if (ImGui::BeginPopupContextItem("FileContext")) {
    if (ImGui::MenuItem("Open")) { /* ... */ }
    if (ImGui::MenuItem("Rename")) { /* ... */ }
    if (ImGui::MenuItem("Delete")) { /* ... */ }
    ImGui::EndPopup();
}

// Window background context menu
if (ImGui::BeginPopupContextWindow("WindowContext")) {
    if (ImGui::MenuItem("Add Item")) { /* ... */ }
    ImGui::EndPopup();
}

For manual control, use OpenPopupOnItemClick followed by BeginPopup if you need custom timing or mouse button configurations.

Adding Tooltips

Tooltips are transient popups that follow the mouse cursor and never take focus. Create them with BeginTooltip or the shortcut SetTooltip. The implementation lives in BeginTooltipEx (see imgui_internal.h), which flags the temporary window with ImGuiWindowFlags_Tooltip (line 1199 in imgui.h).

Always guard BeginTooltip with a hover check to avoid flickering:

ImGui::Button("Hover for Info");
if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) {
    ImGui::BeginTooltip();
    ImGui::Text("Detailed information about this button.");
    ImGui::Text("Line two of the tooltip.");
    ImGui::EndTooltip();
}

For simple text, use the one-liner:

ImGui::SetTooltip("Simple text tooltip");

Internal Architecture and Focus Management

All popup-related data resides in ImGuiContext::BeginPopupStack (declared in imgui_internal.h line 2375). When you call any BeginPopup… function, Dear ImGui creates a temporary ImGuiWindow and inserts it into the global window list with the appropriate flags (Popup, Modal, or Tooltip). These windows are drawn after the main UI pass.

Navigation and focus handling are automatically redirected:

  • Modal popups block navigation to other windows via the ImGuiWindowFlags_Modal flag.
  • Normal popups allow closing by clicking outside or pressing Esc, handled during the input processing stage in imgui.cpp.
  • The ID stack (PushID/PopID) isolates popups, ensuring that identifiers passed to OpenPopup and BeginPopup are scoped correctly against collisions.

Summary

  • Every popup is a window: Modals, context menus, and tooltips are all ImGuiWindow instances with specialized flags.
  • Three-step lifecycle: Call OpenPopup to queue, BeginPopup* to enter the drawing block (returns true while open), and EndPopup to clean up.
  • Modal blocking: Use BeginPopupModal with ImGuiWindowFlags_Modal to block background interaction.
  • Context helpers: BeginPopupContextItem, BeginPopupContextWindow, and BeginPopupContextVoid simplify right-click menus.
  • Tooltip guarding: Wrap BeginTooltip in IsItemHovered checks; use SetTooltip for quick text-only hints.
  • Source locations: Public API is in imgui.h (lines 824-878); internal stack management is in imgui_internal.h and imgui.cpp.

Frequently Asked Questions

How do I prevent a modal from closing when clicking outside or pressing Escape?

According to the imgui.cpp implementation, normal popups automatically close on outside clicks or Esc keys. For modal popups created with BeginPopupModal, this behavior is controlled by the p_open parameter and internal focus management. To keep a modal open regardless of user actions, simply ignore the p_open pointer (pass nullptr) and only close it programmatically via CloseCurrentPopup() when your specific "Close" button is pressed.

What is the difference between BeginPopup and BeginPopupModal?

BeginPopup creates a non-blocking popup that allows interaction with other windows and typically closes when clicking outside. BeginPopupModal (declared in imgui.h line 849) creates a blocking window flagged with ImGuiWindowFlags_Modal that disables interaction with all other windows, dims the background, and requires explicit dismissal via CloseCurrentPopup() or clearing the p_open boolean.

Can I open a context menu with a left-click instead of a right-click?

Yes. The helper BeginPopupContextItem accepts ImGuiPopupFlags as its second parameter. Pass ImGuiPopupFlags_MouseButtonLeft to trigger on left-click instead of the default right-click (MouseButtonRight). Similarly, OpenPopupOnItemClick accepts an optional mouse button index (0=left, 1=right, 2=middle).

Why does my tooltip flicker or not appear at all?

Tooltips must be drawn every frame while the condition is true. If you call BeginTooltip unconditionally, it will flicker because it lacks a stable window ID. Always wrap tooltip code in a hover check such as if (ImGui::IsItemHovered()) or if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) to ensure the window is only submitted when needed, maintaining consistent focus and positioning.

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 →