How Dear ImGui's Immediate Mode GUI Paradigm Differs from Retained-Mode UI Toolkits

Dear ImGui implements an immediate mode GUI where UI elements are recreated and processed every frame through direct function calls that handle both layout and interaction in a single pass, eliminating persistent widget objects.

The immediate mode GUI architecture in the ocornut/imgui repository fundamentally reimagines how user interfaces are constructed and rendered. Unlike traditional toolkits that maintain long-lived object hierarchies, Dear ImGui rebuilds the entire interface from scratch each frame using stateless function calls. This approach places UI logic directly in the application loop while the library handles efficient batching and rendering behind the scenes.

Core Principles of Immediate Mode GUI

Stateless Rendering Without Persistent Objects

In Dear ImGui's immediate mode paradigm, functions like ImGui::Button("OK") do not instantiate persistent widget objects. Instead, each call queries the current input state, determines hover and click status, updates minimal internal state, and immediately returns a boolean result. According to the source code in imgui.cpp, this design eliminates the need for a separate UI object model that exists across frames.

Single-Frame Data Lifecycle

All UI data in the immediate mode GUI lives only for the duration of the current frame. If your application needs to persist values—such as a slider's current position—that state must be stored in your own variables and passed back to ImGui on subsequent frames. The library maintains only essential navigation and focus state internally, as defined in imgui.h.

Implicit UI Hierarchy

Rather than constructing a tree of widget objects that persist in memory, the immediate mode GUI hierarchy is implicitly defined by the order of function calls each frame. When you call ImGui::Begin("Window") followed by ImGui::SliderFloat(), the nesting structure exists only for that specific frame's execution context.

Immediate Mode vs. Retained Mode: Key Differences

Understanding the architectural contrast between these paradigms clarifies why Dear ImGui adopts its specific approach:

  • Widget Lifecycle: Immediate mode creates, processes, and destroys UI elements each frame with no long-lived objects, while retained mode instantiates widgets once that persist until explicitly destroyed.

  • Event Handling: Immediate mode polls events directly inside widget functions that return interaction flags immediately, whereas retained mode dispatches events to existing objects via callbacks or listener patterns.

  • State Storage: Immediate mode requires the application to store all persistent state; ImGui keeps only minimal internal data for navigation and focus management. Retained mode embeds state directly within widget objects (text content, selection ranges, etc.).

  • Performance Characteristics: Despite rebuilding the UI every frame, Dear ImGui does not issue a draw call per widget. As implemented in imgui_draw.cpp, the library batches geometry into vertex buffers and emits a small list of draw commands. This avoids the "hammering the GPU" pitfall mentioned in docs/README.md. Retained-mode engines may batch internally but often require full scene graph traversal each frame.

  • API Complexity: Immediate mode offers a simpler API where you write UI code inline where needed, while retained mode requires maintaining separate widget objects and hooking them up to data models.

Implementation Architecture in Dear ImGui

The immediate mode GUI implementation spans several key files in the repository:

  • imgui.h: Exposes the public API with immediate-mode functions including ImGui::Begin(), ImGui::Button(), and ImGui::SliderFloat().

  • imgui.cpp: Contains the core implementation of the UI state machine, input handling logic, and the draw-list generation that translates immediate calls into renderable data.

  • imgui_draw.cpp: Handles vertex buffer construction and draw-list batching, ensuring that multiple widget calls collapse into efficient GPU commands.

  • backends/imgui_impl_opengl3.cpp: Demonstrates how renderer backends consume ImGui's draw data and submit it to the GPU, illustrating the separation between immediate-mode UI logic and actual rendering.

Practical Implementation Examples

The following pattern demonstrates the immediate mode GUI inside a typical game loop:

// Example: simple window with a button and a slider
bool show_demo = true;
float value = 0.0f;

ImGui::Begin("Demo Window", &show_demo);           // Re-creates the window each frame
if (ImGui::Button("Press Me")) {                  // Returns true on click
    // Handle click immediately
    value = 0.0f;
}
ImGui::SliderFloat("Value", &value, 0.0f, 1.0f); // Reads/writes the external variable
ImGui::End();                                      // Window layout is finalized

This example shows how the immediate mode GUI processes interaction immediately within the same frame:

// Immediate-mode style UI inside a game loop
while (running) {
    // 1. Gather input, start new ImGui frame
    ImGui_ImplXXX_NewFrame();
    ImGui::NewFrame();

    // 2. Build UI (the immediate-mode pass)
    ShowDemoWindow(&show_demo);

    // 3. Render: ImGui builds draw-list, then back-end draws it
    ImGui::Render();
    ImGui_ImplXXX_RenderDrawData(ImGui::GetDrawData());

    // 4. Swap buffers, etc.
}

In this loop, ImGui::NewFrame() resets internal state, your UI code executes the immediate mode pass, and ImGui::Render() generates the batched draw data that the backend submits to the GPU.

Summary

  • Dear ImGui uses an immediate mode GUI where widgets exist only for the current frame and are recreated through function calls every loop iteration.

  • State management is the application's responsibility; the library queries external variables rather than owning persistent widget state.

  • The API design eliminates boilerplate by handling layout and interaction in a single pass without requiring object instantiation or event listener registration.

  • Despite the per-frame reconstruction, rendering remains efficient through vertex batching in imgui_draw.cpp, not individual draw calls per widget.

  • The architecture is defined in imgui.h and imgui.cpp, with platform-specific rendering handled by backend implementations like imgui_impl_opengl3.cpp.

Frequently Asked Questions

Does immediate mode GUI mean Dear ImGui redraws every pixel individually each frame?

No. While the UI is logically rebuilt every frame through function calls, Dear ImGui batches all geometry into vertex buffers and emits a minimal set of draw commands. As noted in docs/README.md, this distinction prevents the "hammering the GPU" behavior associated with naive immediate mode rendering.

Where is widget state stored in an immediate mode GUI?

Widget state is stored in your application variables, not inside ImGui objects. When calling ImGui::SliderFloat("Value", &value, 0.0f, 1.0f), the library reads from and writes to your value variable directly. The only state ImGui retains internally involves navigation, focus management, and temporary frame data.

How does event handling work without persistent widget objects?

Events are polled synchronously inside the widget function. When you call ImGui::Button("OK"), it immediately checks the current input state and returns true if clicked during that frame. There are no callbacks or event queues; interaction results are available instantly as return values.

Can immediate mode GUIs handle complex UI hierarchies efficiently?

Yes. Dear ImGui manages complex layouts through stack-based context tracking in imgui.cpp. While the hierarchy is rebuilt each frame, the library maintains internal stacks for window clipping, layout positioning, and ID hashing that enable efficient processing of nested containers without persistent scene graphs.

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 →