Skip to main content
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();
label
const char*
required
Widget label
preview_value
const char*
required
Text displayed in the combo box before opening
flags
ImGuiComboFlags
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);
const char* items[] = { "AAA", "BBB", "CCC", "DDD" };
static int item_current = 0;
ImGui::Combo("Combo", &item_current, 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);

Button Style

// 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
ImVec2
  • 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();
}

Performance Tips

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.

Build docs developers (and LLMs) love