How to Implement Theming and Custom Styling in Dear ImGui (ImGuiStyle & ImGuiCol)

Dear ImGui stores all visual parameters—colors, padding, rounding, and border sizes—in the ImGuiStyle structure, which you can modify globally via ImGui::GetStyle() or temporarily using PushStyleColor and PushStyleVar.

The ocornut/imgui repository provides a comprehensive styling system that separates color palettes (ImGuiCol_ enums) from dimensional variables (ImGuiStyleVar_ enums). Understanding how to leverage the ImGuiStyle structure and the push/pop stack system allows you to create persistent custom themes or apply temporary visual overrides for specific windows and widgets.

Understanding ImGuiStyle and ImGuiCol

All visual configuration in Dear ImGui lives in the ImGuiStyle structure declared in imgui.h (line 208). This struct contains dimensional properties like WindowRounding, FramePadding, and Alpha, plus a Colors array that holds the entire RGBA palette.

According to the source in imgui.h (lines 225), the member Colors[ImGuiCol_COUNT] stores color values as ImU32 or ImVec4 depending on the API used. The enum definitions categorize these into two distinct groups:

  • ImGuiStyleVar_… (lines 1814–1864): Controls float and ImVec2 fields such as WindowRounding, FramePadding, and ItemSpacing
  • ImGuiCol_… (lines 1825–1840): Defines color entries for every UI element from ImGuiCol_WindowBg to ImGuiCol_PlotHistogram

Built-in Base Themes

The framework provides three entry-point functions in imgui.h (lines 421–423) to initialize a clean palette:

  1. ImGui::StyleColorsDark(ImGuiStyle* dst = NULL) – Default dark theme with high contrast
  2. ImGui::StyleColorsLight(ImGuiStyle* dst = NULL) – Light-bordered theme for bright environments
  3. ImGui::StyleColorsClassic(ImGuiStyle* dst = NULL) – Classic legacy look from older ImGui versions

These functions populate an ImGuiStyle structure with sensible defaults. You should call one of these after ImGui::CreateContext() but before your first ImGui::NewFrame().

Global Style Modification

For persistent theme changes that affect the entire application, obtain a reference to the global style using ImGui::GetStyle() (declared in imgui.h line 402) and modify its members directly.

ImGuiStyle& style = ImGui::GetStyle();          // Reference to global style
ImGui::StyleColorsDark(&style);                // Initialize with dark palette

// Modify dimensional properties
style.Alpha                  = 0.95f;
style.WindowRounding         = 6.0f;
style.FrameRounding          = 4.0f;
style.ScrollbarRounding      = 5.0f;

// Override specific colors in the palette
style.Colors[ImGuiCol_TitleBgActive]  = ImVec4(0.45f, 0.15f, 0.75f, 1.00f);
style.Colors[ImGuiCol_Button]         = ImVec4(0.30f, 0.30f, 0.80f, 0.40f);
style.Colors[ImGuiCol_ButtonHovered]  = ImVec4(0.30f, 0.30f, 0.80f, 1.00f);
style.Colors[ImGuiCol_ButtonActive]   = ImVec4(0.15f, 0.15f, 0.45f, 1.00f);

Changes to GetStyle() modify the active context's style permanently until you change them again or call another base theme function.

Temporary Style Overrides

For per-frame or localized modifications that should not affect the global theme, use the push/pop stack system. These functions (declared in imgui.h lines 529–537) automatically restore previous values when you call the corresponding pop function.

Color overrides:

ImGui::PushStyleColor(ImGuiCol idx, ImU32 col);
ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col);
ImGui::PopStyleColor(int count = 1);

Variable overrides:

ImGui::PushStyleVar(ImGuiStyleVar idx, float val);
ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val);
ImGui::PopStyleVar(int count = 1);

This approach is essential when you want a specific window or widget to differ from the global theme without affecting subsequent UI elements.

Complete Implementation Examples

Creating a Custom Dark Theme at Startup

Initialize your custom theme once after context creation:

// After ImGui::CreateContext()
ImGuiStyle& style = ImGui::GetStyle();
ImGui::StyleColorsDark(&style);

style.WindowRounding = 6.0f;
style.FrameRounding  = 4.0f;
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.1f, 0.1f, 0.1f, 0.95f);

Per-Window Temporary Style Overrides

Use push/pop to create isolated styling contexts:

ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.1f, 0.1f, 0.1f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 12.0f);

ImGui::Begin("Themed Window");
ImGui::Text("This window uses custom background and rounding");
ImGui::End();

ImGui::PopStyleVar();          // Restore previous rounding
ImGui::PopStyleColor();        // Restore previous background

Runtime Theme Switching

Toggle between light and dark modes dynamically:

bool use_dark = true; // Toggle via UI button

if (use_dark)
    ImGui::StyleColorsDark();
else
    ImGui::StyleColorsLight();

// Re-apply custom tweaks after base palette
ImGui::GetStyle().WindowRounding = 4.0f;

Combining Fonts with Style Scaling

Adjust typography alongside colors:

ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("Roboto-Regular.ttf", 16.0f);
ImGui::GetStyle().ScaleAllSizes(1.1f);   // Enlarge all UI elements proportionally

Summary

  • Global themes: Modify ImGui::GetStyle() directly after calling StyleColorsDark(), StyleColorsLight(), or StyleColorsClassic() from imgui.h (lines 421–423)
  • Temporary changes: Use PushStyleColor() and PushStyleVar() for localized overrides, always pairing with PopStyleColor() and PopStyleVar() (lines 529–537)
  • Color storage: Access via ImGui::GetStyle().Colors[ImGuiCol_...] where the ImGuiCol_ enum spans lines 1825–1840 in imgui.h
  • Dimensional vars: ImGuiStyleVar_ enum defined in lines 1814–1864 controls spacing, rounding, and sizes
  • Source files: Core definitions reside in imgui.h (struct and enums), while imgui_demo.cpp contains the ShowStyleEditor() implementation for live theme editing

Frequently Asked Questions

How do I change the default theme in Dear ImGui?

Call one of the three base theme functions—ImGui::StyleColorsDark(), ImGui::StyleColorsLight(), or ImGui::StyleColorsClassic()—immediately after ImGui::CreateContext() and before your first ImGui::NewFrame(). These functions populate the ImGuiStyle structure stored in the current context with a complete color palette and dimensional defaults.

What is the difference between ImGuiStyleVar and ImGuiCol?

ImGuiStyleVar controls dimensional and scalar properties like WindowRounding, FramePadding, and Alpha, while ImGuiCol defines color indices for the Colors array in ImGuiStyle. When using push/pop APIs, you must use PushStyleVar for dimensional changes and PushStyleColor for color changes, as they manipulate different data types (float/ImVec2 vs ImU32/ImVec4).

When should I use PushStyleColor vs modifying GetStyle() directly?

Modify GetStyle() directly for persistent global themes that should last the entire session or until explicitly changed. Use PushStyleColor and PushStyleVar when you need temporary overrides for a specific window, button, or frame, followed by the corresponding pop calls to restore the previous state. This prevents style changes from leaking into subsequent UI elements.

Where are the style enums defined in the ImGui source?

The ImGuiStyle structure is declared in imgui.h at line 208, with its Colors array defined at line 225. The ImGuiStyleVar_ enum appears at lines 1814–1864, and the ImGuiCol_ enum follows at lines 1825–1840. The push/pop function signatures are located at lines 529–537 in the same header file according to the ocornut/imgui source code.

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 →