# How to Implement Multi-Select Functionality for Lists and Items in Dear ImGui

> Learn to implement multi select for lists in Dear ImGui using BeginMultiSelect API. Enables Ctrl click, Shift click range selection, and drag box select for improved UI interactivity.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-26

---

**Dear ImGui provides a dedicated `BeginMultiSelect()` API that creates an `ImGuiMultiSelectIO` context to handle Ctrl-click toggling, Shift-click range selection, and box-select drag operations when rendering items with `Selectable()` and the `ImGuiSelectableFlags_SelectOnNav` flag.**

The ocornut/imgui repository includes a comprehensive multi-select system that manages selection state, keyboard navigation, and complex selection patterns through a structured begin/end API. This implementation, found in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) and [`imgui_widgets.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_widgets.cpp), allows developers to build list widgets supporting multiple selection modalities without manually tracking keyboard modifiers or drag rectangles.

## Understanding the Dear ImGui Multi-Select Architecture

The multi-select API operates through a temporary state object stored in the current ImGui context (`g.CurrentMultiSelect`). When you call `ImGui::BeginMultiSelect()`, the function returns an `ImGuiMultiSelectIO*` pointer that tracks selection requests, range operations, and box-select geometry for the duration of the block.

According to the implementation in [`imgui_widgets.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_widgets.cpp) (lines 7395-7587), `Selectable()` widgets automatically communicate with the active multi-select context when the `ImGuiSelectableFlags_SelectOnNav` flag is present. This flag ensures that keyboard or gamepad navigation automatically selects focused items, while mouse interactions generate toggle requests stored in the IO structure.

The system separates input detection from state application. While the block is active, ImGui records selection requests (such as "select items 3-7" from a Shift-click). After rendering all items, you process these requests using `ImGui::ApplyRequests()` and synchronize your external storage with the `ms_io->Selection` bit array.

## Step-by-Step Implementation Guide

### Step 1: Initialize the Multi-Select Context

Call `ImGui::BeginMultiSelect()` before drawing your list items. This function accepts scope flags, your current selection size, and the total item count:

```cpp
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(
    ImGuiMultiSelectFlags_ScopeWindow,   // Enables box-select across the window
    selection.Size,                      // Current selection count (-1 if unknown)
    items.Size);                        // Total items (-1 if unknown)

```

The `ImGuiMultiSelectFlags_ScopeWindow` flag establishes that box-select operations and "click outside to clear" behavior apply to the entire window hosting the widget. Alternatively, `ImGuiMultiSelectFlags_ScopeRect` limits these interactions to the rectangular area between your `BeginMultiSelect` and `EndMultiSelect` calls, which is essential when hosting multiple selectable lists in the same window.

### Step 2: Render Items Using Selectable with SelectOnNav

For each item in your list, call `ImGui::Selectable()` with the `ImGuiSelectableFlags_SelectOnNav` flag. You can use either the pointer-based approach or the query-based approach:

**Pointer-based modification:**

```cpp
for (int n = 0; n < items.Size; n++)
{
    bool selected = selection[n];
    if (ImGui::Selectable(items[n], &selected, 
                          ImGuiSelectableFlags_SelectOnNav))
        selection[n] = selected;  // ImGui modified 'selected' if user clicked
}

```

**Query-based toggle detection:**

```cpp
for (int n = 0; n < items.Size; n++)
{
    ImGui::Selectable(items[n], false, ImGuiSelectableFlags_SelectOnNav);
    if (ImGui::IsItemToggledSelection())
        selection[n] = !selection[n];  // Toggle detected after rendering
}

```

The `ImGuiSelectableFlags_SelectOnNav` flag is mandatory for proper multi-select behavior, as it forwards navigation-based selection events to the `ImGuiMultiSelectIO` structure.

### Step 3: Apply Selection Requests

After drawing all items, process accumulated selection requests from Shift-clicks and box-select operations:

```cpp
ImGui::ApplyRequests(ms_io);  // Processes range requests into ms_io->Selection

// Synchronize your external storage with ImGui's selection state
for (int n = 0; n < items.Size; n++)
    selection[n] = ms_io->Selection[n];

```

The `ApplyRequests` function, implemented in [`imgui_widgets.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_widgets.cpp) (lines 8700-8800), converts complex user interactions into simple boolean array updates.

### Step 4: Finalize with EndMultiSelect

Close the multi-select block to finalize box-select state and cleanup:

```cpp
ImGui::EndMultiSelect(ms_io);

```

While the `ImGuiMultiSelectIO` pointer's destructor automatically handles cleanup, explicit closure ensures proper scope management.

## Essential Flags for Multi-Select Configuration

- **ImGuiMultiSelectFlags_SingleSelect**: Restricts selection to one item, creating radio-list behavior while retaining the multi-select framework.

- **ImGuiMultiSelectFlags_ScopeWindow**: Defines the selection scope as the entire window, allowing box-select to originate anywhere in the window and clearing selection when clicking outside items.

- **ImGuiMultiSelectFlags_ScopeRect**: Limits box-select and clear-on-outside to the rectangle between Begin/End calls, isolating multiple lists within the same window.

- **ImGuiSelectableFlags_SelectOnNav**: Required flag for `Selectable()` that enables automatic selection when navigation focus enters an item, critical for keyboard and gamepad support.

- **ImGuiSelectableFlags_AllowOverlap**: Permits hit-testing of overlapping items, useful when list entries contain embedded buttons or controls.

## Complete Working Examples

### Basic Vector-Based Selection

This example demonstrates the standard pattern using `ImVector<bool>` for selection storage:

```cpp
void ShowMultiSelectList()
{
    static const char* items[] = { "Apple", "Banana", "Cherry", "Date", "Elderberry" };
    static ImVector<bool> selection;
    if (selection.empty()) 
        selection.resize(IM_ARRAYSIZE(items), false);

    // Step 1: Begin multi-select context
    ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(
        ImGuiMultiSelectFlags_ScopeWindow,
        selection.Size,
        IM_ARRAYSIZE(items));

    // Step 2: Render selectable items
    for (int n = 0; n < IM_ARRAYSIZE(items); n++)
    {
        bool selected = selection[n];
        if (ImGui::Selectable(items[n], &selected,
                              ImGuiSelectableFlags_SelectOnNav))
            selection[n] = selected;
    }

    // Step 3: Apply requests and sync storage
    ImGui::ApplyRequests(ms_io);
    for (int n = 0; n < IM_ARRAYSIZE(items); n++)
        selection[n] = ms_io->Selection[n];

    // Step 4: End context
    ImGui::EndMultiSelect(ms_io);
}

```

### Custom Storage Synchronization

For applications requiring custom data structures, implement a synchronization method:

```cpp
struct SelectionStorage
{
    ImVector<bool> Selected;
    
    void SyncFrom(const ImGuiMultiSelectIO* ms_io)
    {
        for (int i = 0; i < Selected.Size; i++)
            Selected[i] = ms_io->Selection[i];
    }
};

void ShowCustomStorageList()
{
    static const char* items[] = { "One", "Two", "Three", "Four" };
    static SelectionStorage storage;
    if (storage.Selected.empty()) 
        storage.Selected.resize(IM_ARRAYSIZE(items), false);

    ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(
        ImGuiMultiSelectFlags_ScopeWindow,
        storage.Selected.Size,
        IM_ARRAYSIZE(items));

    for (int i = 0; i < IM_ARRAYSIZE(items); ++i)
    {
        bool selected = storage.Selected[i];
        ImGui::Selectable(items[i], &selected, 
                          ImGuiSelectableFlags_SelectOnNav);
        storage.Selected[i] = selected;
    }

    ImGui::ApplyRequests(ms_io);
    storage.SyncFrom(ms_io);  // Custom synchronization
    ImGui::EndMultiSelect(ms_io);
}

```

Reference implementations demonstrating manual and API-driven approaches appear in [`imgui_demo.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_demo.cpp) (lines 2780-3060).

## Summary

- **Initialize context**: Use `ImGui::BeginMultiSelect()` with scope flags before rendering items.
- **Render with navigation**: Always include `ImGuiSelectableFlags_SelectOnNav` when calling `ImGui::Selectable()`.
- **Process requests**: Call `ImGui::ApplyRequests()` after rendering to handle Shift-clicks and box-select.
- **Synchronize storage**: Copy the `ms_io->Selection` array to your external storage after applying requests.
- **Close properly**: End blocks with `ImGui::EndMultiSelect()` to finalize state.
- **Source references**: Public API resides in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (lines 51-66), implementation in [`imgui_widgets.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_widgets.cpp) (lines 7395-7587), and demos in [`imgui_demo.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_demo.cpp).

## Frequently Asked Questions

### What is the difference between ScopeWindow and ScopeRect?

`ImGuiMultiSelectFlags_ScopeWindow` allows box-select operations to start anywhere within the host window and clears selection when clicking on window background. `ImGuiMultiSelectFlags_ScopeRect` restricts these interactions to the rectangular area defined between `BeginMultiSelect()` and `EndMultiSelect()`, which prevents interference when displaying multiple selectable lists in the same window.

### How do I detect selection toggles without using the bool pointer parameter?

Call `ImGui::IsItemToggledSelection()` immediately after `ImGui::Selectable()`. This function returns true if the item was toggled during that frame, allowing you to write `if (ImGui::IsItemToggledSelection()) selection[i] = !selection[i];` instead of passing a pointer to `Selectable()`.

### Can I use multi-select with TreeNode instead of Selectable?

Yes, the multi-select API works with any item bounding box, including `TreeNode()` widgets. Ensure you set `ImGuiTreeNodeFlags_OpenOnArrow` and handle selection state appropriately, though `Selectable()` remains the primary widget for list-based multi-selection as demonstrated in [`imgui_demo.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_demo.cpp).

### How do I implement single-select behavior using this API?

Pass `ImGuiMultiSelectFlags_SingleSelect` to `ImGui::BeginMultiSelect()`. This flag enforces that only one item can be selected at a time, automatically clearing previous selections when a new item is chosen, effectively creating a radio-list behavior while maintaining the full navigation and interaction framework.