# How to Create and Manage Popup Menus, Context Menus, and Modal Dialogs in Dear ImGui

> Master Dear ImGui popup menus context menus and modal dialogs. Learn to create and manage them with BeginPopup OpenPopup and BeginPopupModal for efficient UIs.

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

---

**Dear ImGui implements popups as specialized windows managed through `BeginPopup()`, `OpenPopup()`, and `BeginPopupModal()`, using an internal stack (`ImGuiContext::BeginPopupStack`) to handle hierarchical levels and automatic closing behavior.**

Creating overlays that capture or pass through user input is a core UI pattern in the **ocornut/imgui** immediate-mode library. Unlike traditional retained-mode UI frameworks, Dear ImGui treats popup menus, context menus, and modal dialogs as transient window states that you declare every frame. Understanding the relationship between the open-request queue (`g.OpenPopupStack`) and the active popup stack is essential for building robust interfaces.

## Popup Architecture and the Internal Stack

All popup variants in Dear ImGui share a common internal infrastructure defined in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp). When you call `OpenPopup()`, the system pushes an identifier onto `ImGuiContext::OpenPopupStack`. During the next frame, `BeginPopup()` checks this stack, and if the ID matches, it pushes a new level onto `ImGuiContext::BeginPopupStack` via `BeginPopupEx()` (located around lines 12681–12697 in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)).

Key architectural constraints from the source code:

- **Identifiers are relative to the current ID stack.** As documented in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 846–850), `OpenPopup()` and `BeginPopup()` must be called at the same ID level; otherwise, the popup will never match its open request.
- **Window flags are forwarded.** `BeginPopupEx()` forwards your `ImGuiWindowFlags` to the underlying window creation, setting `ImGuiWindowFlags_Popup` or `ImGuiWindowFlags_Modal` internally.
- **Automatic lifecycle management.** Popups close automatically when users click outside the bounds, press **Esc**, or when you explicitly call `CloseCurrentPopup()`. The closing logic resides in `ClosePopupToLevel()` (lines 12726–12736 in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)).

## Creating Standard Popup Menus

Standard popup menus are transient overlays that appear near a triggering widget and disappear when focus is lost. The API follows a request-then-build pattern:

1. **Request the popup** with `OpenPopup(const char* str_id)` to mark it as open for the next frame.
2. **Begin the contents** with `BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0)`, which returns `true` only while the popup is active.
3. **End the block** with `EndPopup()`.

```cpp
if (ImGui::Button("Options"))
    ImGui::OpenPopup("options_popup");

if (ImGui::BeginPopup("options_popup"))
{
    if (ImGui::MenuItem("Refresh"))  { /* handle refresh */ }
    if (ImGui::MenuItem("Settings")) { /* handle settings */ }
    ImGui::Separator();
    if (ImGui::MenuItem("Quit"))     { /* handle quit */ }
    ImGui::EndPopup();
}

```

Because popups are just windows, you can embed any ImGui widgets inside them, including tables, sliders, or child regions.

## Implementing Context Menus

Context menus are specialized popups triggered by mouse input, typically right-clicks. Dear ImGui provides convenience helpers in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 875–880) that combine `OpenPopupOnItemClick()` and `BeginPopup()` into a single call:

- **`BeginPopupContextItem()`**: Attaches to the last drawn item's ID.
- **`BeginPopupContextWindow()`**: Attaches to the current window background.
- **`BeginPopupContextVoid()`**: Attaches to the full screen void (no window).

These wrappers default to the right mouse button but accept `ImGuiPopupFlags` to customize the trigger:

```cpp
ImGui::Text("Right-click me");
if (ImGui::BeginPopupContextItem())  // Automatically uses last item ID
{
    if (ImGui::MenuItem("Delete"))    { /* ... */ }
    if (ImGui::MenuItem("Duplicate")) { /* ... */ }
    ImGui::EndPopup();
}

// Left-click version
if (ImGui::BeginPopupContextItem("left_context", ImGuiPopupFlags_MouseButtonLeft))
{
    // Left-click menu items
    ImGui::EndPopup();
}

```

## Building Modal Dialogs

**Modal dialogs** block interaction with every other ImGui window until dismissed. They dim the background and optionally display a title bar. Use `BeginPopupModal()` instead of `BeginPopup()`:

```cpp
bool open = true;
if (ImGui::Button("Delete file"))
    ImGui::OpenPopup("confirm_delete");

if (ImGui::BeginPopupModal("confirm_delete", &open, ImGuiWindowFlags_AlwaysAutoResize))
{
    ImGui::Text("Are you sure you want to delete this file?");
    
    if (ImGui::Button("Yes"))
    {
        // Perform deletion logic
        ImGui::CloseCurrentPopup();  // Explicit close
    }
    ImGui::SameLine();
    if (ImGui::Button("Cancel"))
    {
        ImGui::CloseCurrentPopup();  // or set open = false
    }
    ImGui::EndPopup();
}

```

The `bool* p_open` parameter allows external control over the modal's lifetime. When passing `nullptr`, you must rely exclusively on `CloseCurrentPopup()` or the automatic close behaviors.

## Managing Popup Lifetime and State

Understanding when popups close is critical for state management:

- **Implicit closing**: Selecting a `MenuItem` or `Selectable` automatically closes the current popup level.
- **Explicit closing**: Call `CloseCurrentPopup()` to dismiss the topmost popup immediately.
- **Focus loss**: Clicking outside the popup rectangle or pressing **Esc** triggers `ClosePopupToLevel()`, unwinding the `BeginPopupStack`.

Because the popup system uses the ID stack, nested popups are fully supported. Each `BeginPopup()` call creates a new scope, and `EndPopup()` restores the previous state.

## Summary

- **Dear ImGui popups** are managed through `OpenPopup()`, `BeginPopup()`, and `EndPopup()`, with modal variants using `BeginPopupModal()`.
- **Context menu helpers** like `BeginPopupContextItem()` wrap input detection and popup creation for common right-click patterns.
- **Popup identifiers** must match between `OpenPopup()` and `BeginPopup()` calls at the same ID stack depth, as enforced in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h).
- **Automatic cleanup** occurs via `ClosePopupToLevel()` when users click outside or press **Esc**, while `CloseCurrentPopup()` provides programmatic control.
- **Reference implementations** for all patterns are available in [`imgui_demo.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_demo.cpp), with core logic in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) and API definitions in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h).

## Frequently Asked Questions

### What is the difference between `OpenPopup()` and `BeginPopup()`?

`OpenPopup()` queues a request to open a popup on the next frame by pushing an ID onto `ImGuiContext::OpenPopupStack`. `BeginPopup()` checks that queue, and if the ID matches, it begins the actual window scope and returns `true`. You must call `OpenPopup()` before `BeginPopup()` will ever succeed.

### Why is my popup not appearing when I call `BeginPopup()`?

The most common cause is an **ID stack mismatch**. According to the implementation in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), `BeginPopup()` compares the requested ID against `g.OpenPopupStack` using the current ID stack scope. If you called `OpenPopup()` inside a `PushID()` block but call `BeginPopup()` outside that block (or vice versa), the hashes will not match. Ensure both calls occur at the same stack level.

### How do I programmatically close a modal dialog from within the popup?

Use **`CloseCurrentPopup()`**. This function (defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) and implemented in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)) marks the current popup level for closure, causing it to disappear at the end of the frame. Alternatively, if you passed a boolean pointer to `BeginPopupModal()` as the `p_open` argument, setting that boolean to `false` will also close the modal.

### Can I nest popups inside other popups?

Yes. Dear ImGui supports nested popup hierarchies through `ImGuiContext::BeginPopupStack`. Each call to `BeginPopup()` pushes a new level onto this stack. Child popups must follow the same `OpenPopup()` then `BeginPopup()` pattern, and they will automatically close if the parent closes. The stack unwinds correctly when `EndPopup()` is called for each level.