Overview
Beyond basic color and style modifications, Dear ImGui provides powerful customization capabilities including DPI scaling, custom rendering, and advanced theming techniques.
DPI Scaling
Font Scaling
Since v1.92 (June 2025), fonts may be dynamically used at any size.
Select default size:
ImGuiStyle& style = ImGui::GetStyle();
style.FontSizeBase = 20.0f;
Scale all fonts:
style.FontScaleDpi = 2.0f;
Change font size dynamically:
// This will be multiplied by style.FontScaleDpi
ImGui::PushFont(NULL, 42.0f);
ImGui::Text("Large text");
ImGui::PopFont();
Change font and font size:
ImGui::PushFont(new_font, 42.0f);
ImGui::Text("Large custom font");
ImGui::PopFont();
Style Scaling
Style scaling is still work in progress. Expect changes in future releases.
For single viewport applications, you can scale all sizes once:
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(2.0f); // Call once at initialization!
If you need to change the scaling factor, reset the style and call ScaleAllSizes() again with a new value.
DPI-Aware Windows Applications
On Windows, you must inform the OS that your application is DPI aware:
Pass SDL_WINDOW_ALLOW_HIGHDPI flag to SDL_CreateWindow() and call ::SetProcessDPIAware().SDL_Window* window = SDL_CreateWindow(
"My App",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
1280, 720,
SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI
);
::SetProcessDPIAware();
Pass SDL_WINDOW_HIGH_PIXEL_DENSITY flag to SDL_CreateWindow().SDL_Window* window = SDL_CreateWindow(
"My App",
1280, 720,
SDL_WINDOW_OPENGL | SDL_WINDOW_HIGH_PIXEL_DENSITY
);
DPI awareness is handled automatically by GLFW.
Use ImGui_ImplWin32_EnableDpiAwareness() helper or an application manifest file.#include "imgui_impl_win32.h"
ImGui_ImplWin32_EnableDpiAwareness();
Conditional Styling
Apply different styles based on widget state:
bool is_error = true;
if (is_error) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
}
ImGui::Text("Status: Error");
if (is_error) {
ImGui::PopStyleColor();
}
Style Stack Management
Use a counter to manage complex push/pop sequences:
int style_count = 0;
if (condition1) {
ImGui::PushStyleColor(ImGuiCol_Button, color1);
style_count++;
}
if (condition2) {
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color2);
style_count++;
}
// Your UI code
if (style_count > 0) {
ImGui::PopStyleColor(style_count);
}
Create clickable areas without visual button appearance:
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.3f, 0.3f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.5f, 0.5f, 0.5f, 0.5f));
if (ImGui::Button("Invisible Button", ImVec2(200, 50))) {
// Handle click
}
ImGui::PopStyleColor(3);
Borderless Windows
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::Begin("Borderless", nullptr, ImGuiWindowFlags_NoTitleBar);
// Window content
ImGui::End();
ImGui::PopStyleVar(2);
Custom Colors and Themes
Creating a Custom Theme
void ApplyDarkTheme()
{
ImGuiStyle& style = ImGui::GetStyle();
ImVec4* colors = style.Colors;
// Base colors
const ImVec4 bg_color = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
const ImVec4 bg_color_light = ImVec4(0.20f, 0.22f, 0.24f, 1.00f);
const ImVec4 accent = ImVec4(0.40f, 0.60f, 0.90f, 1.00f);
const ImVec4 accent_light = ImVec4(0.50f, 0.70f, 1.00f, 1.00f);
const ImVec4 accent_dark = ImVec4(0.30f, 0.50f, 0.80f, 1.00f);
// Window
colors[ImGuiCol_WindowBg] = bg_color;
colors[ImGuiCol_ChildBg] = bg_color;
colors[ImGuiCol_PopupBg] = bg_color_light;
// Text
colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
// Frames
colors[ImGuiCol_FrameBg] = bg_color_light;
colors[ImGuiCol_FrameBgHovered] = accent;
colors[ImGuiCol_FrameBgActive] = accent_dark;
// Buttons
colors[ImGuiCol_Button] = accent;
colors[ImGuiCol_ButtonHovered] = accent_light;
colors[ImGuiCol_ButtonActive] = accent_dark;
// Headers
colors[ImGuiCol_Header] = accent;
colors[ImGuiCol_HeaderHovered] = accent_light;
colors[ImGuiCol_HeaderActive] = accent_dark;
// Tabs
colors[ImGuiCol_Tab] = bg_color_light;
colors[ImGuiCol_TabHovered] = accent_light;
colors[ImGuiCol_TabSelected] = accent;
colors[ImGuiCol_TabSelectedOverline] = accent_light;
// Title
colors[ImGuiCol_TitleBg] = bg_color;
colors[ImGuiCol_TitleBgActive] = bg_color_light;
colors[ImGuiCol_TitleBgCollapsed] = bg_color;
// Scrollbar
colors[ImGuiCol_ScrollbarBg] = bg_color;
colors[ImGuiCol_ScrollbarGrab] = bg_color_light;
colors[ImGuiCol_ScrollbarGrabHovered] = accent;
colors[ImGuiCol_ScrollbarGrabActive] = accent_dark;
// Style properties
style.WindowRounding = 6.0f;
style.FrameRounding = 4.0f;
style.ScrollbarRounding = 6.0f;
style.GrabRounding = 4.0f;
style.TabRounding = 4.0f;
}
Theme Selector
const char* themes[] = { "Dark", "Light", "Classic", "Custom" };
static int current_theme = 0;
if (ImGui::Combo("Theme", ¤t_theme, themes, IM_COUNTOF(themes))) {
switch (current_theme) {
case 0: ImGui::StyleColorsDark(); break;
case 1: ImGui::StyleColorsLight(); break;
case 2: ImGui::StyleColorsClassic(); break;
case 3: ApplyDarkTheme(); break;
}
}
Using Reference Values
Avoid hardcoded sizes by using reference values:
// Use font size as reference
float button_height = ImGui::GetFontSize() * 2.0f;
float spacing = ImGui::GetFontSize() * 0.5f;
// Use frame height as reference
float item_height = ImGui::GetFrameHeight();
// Create proportional UI
ImVec2 button_size(ImGui::GetFontSize() * 8, ImGui::GetFrameHeight() * 1.5f);
ImGui::Button("Proportional Button", button_size);
Custom Rendering
For complete control over appearance, use the low-level ImDrawList API:
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 p = ImGui::GetCursorScreenPos();
// Draw custom background
draw_list->AddRectFilled(
p,
ImVec2(p.x + 200, p.y + 100),
IM_COL32(50, 50, 50, 255),
5.0f // rounding
);
// Draw custom border
draw_list->AddRect(
p,
ImVec2(p.x + 200, p.y + 100),
IM_COL32(100, 150, 200, 255),
5.0f, // rounding
0, // flags
2.0f // thickness
);
// Reserve space
ImGui::Dummy(ImVec2(200, 100));
Anti-Aliasing Options
Control rendering quality:
ImGuiStyle& style = ImGui::GetStyle();
// Enable/disable anti-aliasing
style.AntiAliasedLines = true; // Anti-aliased lines/borders
style.AntiAliasedLinesUseTex = true; // Use textures for better quality
style.AntiAliasedFill = true; // Anti-aliased filled shapes
// Adjust tessellation quality
style.CurveTessellationTol = 1.25f; // Bezier curve quality
style.CircleTessellationMaxError = 0.30f; // Circle quality
Disabling anti-aliasing can improve performance on resource-constrained systems.
Style Persistence
Save and load custom styles:
// Save style to file
void SaveStyle(const char* filename)
{
ImGuiStyle& style = ImGui::GetStyle();
FILE* f = fopen(filename, "wb");
if (f) {
fwrite(&style, sizeof(ImGuiStyle), 1, f);
fclose(f);
}
}
// Load style from file
void LoadStyle(const char* filename)
{
ImGuiStyle& style = ImGui::GetStyle();
FILE* f = fopen(filename, "rb");
if (f) {
fread(&style, sizeof(ImGuiStyle), 1, f);
fclose(f);
}
}
Debug and Development
Style Editor
Use the built-in editor during development:
ImGui::Begin("Style Editor");
ImGui::ShowStyleEditor();
ImGui::End();
Style Selector
Quickly switch between built-in themes:
if (ImGui::ShowStyleSelector("Theme")) {
// Style was changed
}
Getting Style Colors
Retrieve current color values:
const ImVec4& button_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
ImU32 text_color = ImGui::GetColorU32(ImGuiCol_Text);
- Minimize Push/Pop Operations - Group style changes when possible
- Use Direct Style Modification - For permanent changes, modify
ImGuiStyle directly instead of pushing/popping every frame
- Reduce Rounding - Lower rounding values improve performance
- Disable Anti-Aliasing - On low-end hardware, disable anti-aliasing features
- Optimize Tessellation - Increase tolerance values to reduce polygon count
See Also