Combo boxes (dropdowns) and list boxes provide ways for users to select from a list of options. Dear ImGui offers both simple helper functions and flexible BeginCombo/EndCombo APIs.
Combo Boxes
BeginCombo() / EndCombo()
Manually control combo box contents:
IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0);
IMGUI_API void EndCombo();
Text displayed in the combo box before opening
Optional combo flags (see below)
const char* items[] = { "Apple", "Banana", "Cherry", "Dragon Fruit" };
static int item_current_idx = 0;
const char* combo_preview_value = items[item_current_idx];
if (ImGui::BeginCombo("Fruit", combo_preview_value)) {
for (int n = 0; n < IM_COUNTOF(items); n++) {
const bool is_selected = (item_current_idx == n);
if (ImGui::Selectable(items[n], is_selected))
item_current_idx = n;
// Set initial focus when opening the combo
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
Only call EndCombo() if BeginCombo() returns true!
Simple Combo() Functions
Convenience wrappers for common use cases:
IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count,
int popup_max_height_in_items = -1);
IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros,
int popup_max_height_in_items = -1);
IMGUI_API bool Combo(const char* label, int* current_item,
const char* (*getter)(void* user_data, int idx), void* user_data,
int items_count, int popup_max_height_in_items = -1);
Array of Strings
Null-Separated String
Getter Function
const char* items[] = { "AAA", "BBB", "CCC", "DDD" };
static int item_current = 0;
ImGui::Combo("Combo", &item_current, items, IM_COUNTOF(items));
static int item_current = 0;
ImGui::Combo("Combo", &item_current, "One\0Two\0Three\0Four\0\0");
const char* items[] = { "AAA", "BBB", "CCC" };
static int item_current = 0;
auto getter = [](void* data, int n) -> const char* {
return ((const char**)data)[n];
};
ImGui::Combo("Combo", &item_current, getter, items, IM_COUNTOF(items));
Combo Flags
// Align popup to left (useful if combo is wider than popup)
ImGui::BeginCombo("##combo", preview, ImGuiComboFlags_PopupAlignLeft);
Height
// Small popup (4 items visible)
ImGui::BeginCombo("##combo", preview, ImGuiComboFlags_HeightSmall);
// Regular popup (8 items visible, default)
ImGui::BeginCombo("##combo", preview, ImGuiComboFlags_HeightRegular);
// Large popup (20 items visible)
ImGui::BeginCombo("##combo", preview, ImGuiComboFlags_HeightLarge);
// Largest popup (as many fitting items as possible)
ImGui::BeginCombo("##combo", preview, ImGuiComboFlags_HeightLargest);
// No arrow button
ImGui::BeginCombo("##combo", preview, ImGuiComboFlags_NoArrowButton);
// No preview text (button only)
ImGui::BeginCombo("##combo", preview, ImGuiComboFlags_NoPreview);
// Width matches preview text width
ImGui::BeginCombo("##combo", preview, ImGuiComboFlags_WidthFitPreview);
Combo with Search Filter
Add filtering to combo box contents:
const char* items[] = { "Apple", "Apricot", "Banana", "Blueberry", "Cherry" };
static int item_current_idx = 0;
const char* combo_preview_value = items[item_current_idx];
if (ImGui::BeginCombo("Fruits", combo_preview_value)) {
static ImGuiTextFilter filter;
// Focus search box when opening
if (ImGui::IsWindowAppearing()) {
ImGui::SetKeyboardFocusHere();
filter.Clear();
}
// Search box
filter.Draw("##filter", -FLT_MIN);
// Filtered items
for (int n = 0; n < IM_COUNTOF(items); n++) {
const bool is_selected = (item_current_idx == n);
if (filter.PassFilter(items[n])) {
if (ImGui::Selectable(items[n], is_selected))
item_current_idx = n;
}
}
ImGui::EndCombo();
}
List Boxes
BeginListBox() / EndListBox()
Create a scrollable list:
IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0));
IMGUI_API void EndListBox();
size.x > 0.0f: Custom width
size.x < 0.0f or -FLT_MIN: Right-align
size.x = 0.0f: Use current ItemWidth
size.y > 0.0f: Custom height
size.y < 0.0f or -FLT_MIN: Bottom-align
size.y = 0.0f: Default height (~7 items)
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE" };
static int item_selected_idx = 0;
if (ImGui::BeginListBox("##listbox")) {
for (int n = 0; n < IM_COUNTOF(items); n++) {
const bool is_selected = (item_selected_idx == n);
if (ImGui::Selectable(items[n], is_selected))
item_selected_idx = n;
// Set initial focus when opening
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndListBox();
}
Custom Sized List Box
// Full width, 5 items tall
if (ImGui::BeginListBox("##listbox2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) {
for (int n = 0; n < IM_COUNTOF(items); n++) {
bool is_selected = (item_selected_idx == n);
if (ImGui::Selectable(items[n], is_selected))
item_selected_idx = n;
}
ImGui::EndListBox();
}
Simple ListBox() Function
Convenience wrapper:
IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[],
int items_count, int height_in_items = -1);
IMGUI_API bool ListBox(const char* label, int* current_item,
const char* (*getter)(void* user_data, int idx), void* user_data,
int items_count, int height_in_items = -1);
const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange" };
static int item_current = 1;
ImGui::ListBox("Listbox", &item_current, items, IM_COUNTOF(items), 4);
Highlighting Hovered Items
static int item_selected = 0;
static int item_highlighted = -1;
if (ImGui::BeginListBox("##listbox")) {
for (int n = 0; n < IM_COUNTOF(items); n++) {
const bool is_selected = (item_selected == n);
ImGuiSelectableFlags flags = 0;
if (item_highlighted == n)
flags |= ImGuiSelectableFlags_Highlight;
if (ImGui::Selectable(items[n], is_selected, flags))
item_selected = n;
if (ImGui::IsItemHovered())
item_highlighted = n;
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndListBox();
}
Multi-Column Lists
Combine list boxes with tables:
if (ImGui::BeginListBox("##listbox3", ImVec2(-FLT_MIN, 0))) {
if (ImGui::BeginTable("##table", 3)) {
static int selected = -1;
for (int i = 0; i < 10; i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
char label[32];
sprintf(label, "Item %d", i);
if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
selected = i;
ImGui::TableNextColumn();
ImGui::Text("Column 2");
ImGui::TableNextColumn();
ImGui::Text("Data %d", i * 10);
}
ImGui::EndTable();
}
ImGui::EndListBox();
}
Complete Example
void ShowComboListDemo() {
ImGui::Begin("Combo & List Demo");
// Simple combo
ImGui::Text("Simple Combo:");
const char* items[] = { "Apple", "Banana", "Cherry", "Dragon Fruit" };
static int combo_current = 0;
ImGui::Combo("Fruit", &combo_current, items, IM_COUNTOF(items));
ImGui::Spacing();
// Custom combo with BeginCombo/EndCombo
ImGui::Text("Custom Combo:");
static int item_current_idx = 0;
const char* combo_preview = items[item_current_idx];
if (ImGui::BeginCombo("Custom", combo_preview, ImGuiComboFlags_HeightLarge)) {
for (int n = 0; n < IM_COUNTOF(items); n++) {
const bool is_selected = (item_current_idx == n);
if (ImGui::Selectable(items[n], is_selected))
item_current_idx = n;
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// List box
ImGui::Text("List Box:");
static int list_current = 0;
if (ImGui::BeginListBox("##listbox", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) {
for (int n = 0; n < IM_COUNTOF(items); n++) {
const bool is_selected = (list_current == n);
if (ImGui::Selectable(items[n], is_selected))
list_current = n;
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndListBox();
}
ImGui::End();
}
For large lists, use ImGuiListClipper to only render visible items:
if (ImGui::BeginListBox("##large_list", ImVec2(-FLT_MIN, 0))) {
ImGuiListClipper clipper;
clipper.Begin(1000); // 1000 items
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
char label[32];
sprintf(label, "Item %d", i);
if (ImGui::Selectable(label, selected == i))
selected = i;
}
}
ImGui::EndListBox();
}
Best Practices
Use BeginCombo() / EndCombo() for full control over combo contents, including filtering and custom rendering.
Always call EndCombo() or EndListBox() only if the corresponding Begin function returned true.
Call SetItemDefaultFocus() on the selected item to ensure proper keyboard navigation when the popup opens.