Skip to main content
Dear ImGui’s table API provides powerful features for creating data grids with sorting, resizing, freezing, and more. Tables replaced the old Columns API starting from version 1.80.

Basic Tables

BeginTable() / EndTable()

Create a table:
IMGUI_API bool BeginTable(const char* str_id, int columns, ImGuiTableFlags flags = 0,
                          const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f);
IMGUI_API void EndTable();
str_id
const char*
required
Unique identifier for the table
columns
int
required
Number of columns
flags
ImGuiTableFlags
Table behavior flags (see below)
outer_size
ImVec2
Outer size of the table container
Only call EndTable() if BeginTable() returns true!

Three Ways to Populate Tables

Most flexible - use in loops:
if (ImGui::BeginTable("table1", 3)) {
    for (int row = 0; row < 4; row++) {
        ImGui::TableNextRow();
        for (int column = 0; column < 3; column++) {
            ImGui::TableSetColumnIndex(column);
            ImGui::Text("Row %d Column %d", row, column);
        }
    }
    ImGui::EndTable();
}

Table Rows

TableNextRow()

Advance to the next row:
IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f);
row_flags
ImGuiTableRowFlags
Optional row flags (e.g., ImGuiTableRowFlags_Headers)
min_row_height
float
Minimum row height (includes CellPadding.y * 2)
if (ImGui::BeginTable("table", 2)) {
    // Regular row
    ImGui::TableNextRow();
    ImGui::TableNextColumn(); ImGui::Text("Normal");
    ImGui::TableNextColumn(); ImGui::Text("Row");
    
    // Tall row
    ImGui::TableNextRow(0, 50.0f);
    ImGui::TableNextColumn(); ImGui::Text("Tall");
    ImGui::TableNextColumn(); ImGui::Text("Row");
    
    ImGui::EndTable();
}

Table Columns

TableSetupColumn()

Define column properties:
IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0,
                                float init_width_or_weight = 0.0f, ImGuiID user_id = 0);
label
const char*
required
Column label (used for headers)
flags
ImGuiTableColumnFlags
Column behavior flags
init_width_or_weight
float
Initial width (pixels) or weight (ratio)
if (ImGui::BeginTable("table", 3, ImGuiTableFlags_Resizable)) {
    ImGui::TableSetupColumn("Name");
    ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, 100.0f);
    ImGui::TableSetupColumn("Type");
    ImGui::TableHeadersRow();
    
    for (int row = 0; row < 5; row++) {
        ImGui::TableNextRow();
        ImGui::TableNextColumn(); ImGui::Text("File%d", row);
        ImGui::TableNextColumn(); ImGui::Text("%d KB", row * 10);
        ImGui::TableNextColumn(); ImGui::Text("Document");
    }
    ImGui::EndTable();
}

TableHeadersRow()

Submit a row with header cells:
IMGUI_API void TableHeadersRow();
if (ImGui::BeginTable("table", 3)) {
    ImGui::TableSetupColumn("ID");
    ImGui::TableSetupColumn("Name");
    ImGui::TableSetupColumn("Value");
    ImGui::TableHeadersRow();
    
    // ... table contents ...
    ImGui::EndTable();
}

Table Flags

Sizing Flags

// Default: columns are resizable
ImGuiTableFlags_Resizable

// Fit all columns within available width
ImGuiTableFlags_SizingFixedFit

// Columns stretch to fit available width
ImGuiTableFlags_SizingFixedSame

// Each column takes an equal portion
ImGuiTableFlags_SizingStretchProp

// All columns same width, stretch to fit
ImGuiTableFlags_SizingStretchSame

Border Flags

// All borders
ImGuiTableFlags_Borders

// Equivalent to:
ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV |
ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH

Scrolling Flags

// Enable horizontal scrolling
ImGuiTableFlags_ScrollX

// Enable vertical scrolling
ImGuiTableFlags_ScrollY

Row Flags

// Alternating row background colors
ImGuiTableFlags_RowBg

// Make rows selectable
ImGuiTableFlags_RowClickable

Sorting Flags

// Enable sorting (single column)
ImGuiTableFlags_Sortable

// Allow sorting by multiple columns (Shift+Click)
ImGuiTableFlags_SortMulti

// Allow removing sort by Ctrl+clicking headers
ImGuiTableFlags_SortTristate

Scrolling Tables

Create tables with frozen headers and scrolling:
if (ImGui::BeginTable("table", 3, 
                      ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders,
                      ImVec2(0, 300))) {
    ImGui::TableSetupColumn("ID");
    ImGui::TableSetupColumn("Name");
    ImGui::TableSetupColumn("Value");
    ImGui::TableHeadersRow();
    
    for (int row = 0; row < 100; row++) {
        ImGui::TableNextRow();
        ImGui::TableNextColumn(); ImGui::Text("%04d", row);
        ImGui::TableNextColumn(); ImGui::Text("Item %d", row);
        ImGui::TableNextColumn(); ImGui::Text("%d", row * 100);
    }
    ImGui::EndTable();
}

TableSetupScrollFreeze()

Freeze columns and rows:
IMGUI_API void TableSetupScrollFreeze(int cols, int rows);
if (ImGui::BeginTable("table", 4, ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) {
    ImGui::TableSetupScrollFreeze(1, 1);  // Freeze first column and first row
    ImGui::TableSetupColumn("ID");
    ImGui::TableSetupColumn("Name");
    ImGui::TableSetupColumn("Age");
    ImGui::TableSetupColumn("City");
    ImGui::TableHeadersRow();
    
    // ... table contents ...
    ImGui::EndTable();
}

Sorting

TableGetSortSpecs()

Get sorting specifications:
IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs();
struct MyItem {
    int id;
    const char* name;
    int value;
};

static ImVector<MyItem> items;
if (ImGui::BeginTable("table", 3, ImGuiTableFlags_Sortable | ImGuiTableFlags_RowBg)) {
    ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort);
    ImGui::TableSetupColumn("Name");
    ImGui::TableSetupColumn("Value");
    ImGui::TableHeadersRow();
    
    // Get sort specs
    if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs()) {
        if (sort_specs->SpecsDirty) {
            // Sort your data
            // sort_specs->Specs[0].ColumnUserID
            // sort_specs->Specs[0].ColumnIndex
            // sort_specs->Specs[0].SortDirection (ImGuiSortDirection_Ascending/Descending)
            
            // ... perform sort ...
            
            sort_specs->SpecsDirty = false;
        }
    }
    
    // Display items
    for (const MyItem& item : items) {
        ImGui::TableNextRow();
        ImGui::TableNextColumn(); ImGui::Text("%d", item.id);
        ImGui::TableNextColumn(); ImGui::Text("%s", item.name);
        ImGui::TableNextColumn(); ImGui::Text("%d", item.value);
    }
    ImGui::EndTable();
}

Column Flags

Width

// Auto-sizing width
ImGuiTableColumnFlags_WidthStretch  // Default

// Fixed width
ImGuiTableColumnFlags_WidthFixed

Resizing

// User cannot resize this column
ImGuiTableColumnFlags_NoResize

// Double-click to auto-fit
ImGuiTableColumnFlags_NoAutoResize

Sorting

// Default sort direction
ImGuiTableColumnFlags_DefaultSort

// User cannot sort this column
ImGuiTableColumnFlags_NoSort

// Prefer ascending sort
ImGuiTableColumnFlags_PreferSortAscending

// Prefer descending sort
ImGuiTableColumnFlags_PreferSortDescending

Visibility

// Start hidden
ImGuiTableColumnFlags_DefaultHide

// Disable ability to hide column
ImGuiTableColumnFlags_NoHide

Advanced Features

Context Menu

Enable right-click column menu:
ImGui::BeginTable("table", 3, ImGuiTableFlags_ContextMenuInBody);

Hideable Columns

if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Hideable)) {
    ImGui::TableSetupColumn("Column 1");
    ImGui::TableSetupColumn("Column 2", ImGuiTableColumnFlags_DefaultHide);
    ImGui::TableSetupColumn("Column 3");
    ImGui::TableSetupColumn("Column 4");
    ImGui::TableHeadersRow();
    
    // Right-click on headers to show/hide columns
    // ...
    ImGui::EndTable();
}

Reorderable Columns

ImGui::BeginTable("table", 3, ImGuiTableFlags_Reorderable);

Complete Example

void ShowTableDemo() {
    ImGui::Begin("Table Demo");
    
    // Basic table with borders
    if (ImGui::BeginTable("table1", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
        ImGui::TableSetupColumn("Name");
        ImGui::TableSetupColumn("Age");
        ImGui::TableSetupColumn("City");
        ImGui::TableHeadersRow();
        
        ImGui::TableNextRow();
        ImGui::TableNextColumn(); ImGui::Text("Alice");
        ImGui::TableNextColumn(); ImGui::Text("25");
        ImGui::TableNextColumn(); ImGui::Text("New York");
        
        ImGui::TableNextRow();
        ImGui::TableNextColumn(); ImGui::Text("Bob");
        ImGui::TableNextColumn(); ImGui::Text("30");
        ImGui::TableNextColumn(); ImGui::Text("London");
        
        ImGui::TableNextRow();
        ImGui::TableNextColumn(); ImGui::Text("Charlie");
        ImGui::TableNextColumn(); ImGui::Text("35");
        ImGui::TableNextColumn(); ImGui::Text("Tokyo");
        
        ImGui::EndTable();
    }
    
    ImGui::Spacing();
    ImGui::Separator();
    ImGui::Spacing();
    
    // Scrolling table with frozen header
    if (ImGui::BeginTable("table2", 4,
                          ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg |
                          ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable,
                          ImVec2(0, 200))) {
        ImGui::TableSetupScrollFreeze(0, 1);  // Freeze header row
        ImGui::TableSetupColumn("ID");
        ImGui::TableSetupColumn("Name");
        ImGui::TableSetupColumn("Value");
        ImGui::TableSetupColumn("Status");
        ImGui::TableHeadersRow();
        
        for (int row = 0; row < 50; row++) {
            ImGui::TableNextRow();
            ImGui::TableNextColumn(); ImGui::Text("%04d", row);
            ImGui::TableNextColumn(); ImGui::Text("Item %d", row);
            ImGui::TableNextColumn(); ImGui::Text("%d", row * 100);
            ImGui::TableNextColumn(); ImGui::Text(row % 2 ? "Active" : "Inactive");
        }
        ImGui::EndTable();
    }
    
    ImGui::End();
}

Performance Tips

For very large tables, use ImGuiListClipper:
if (ImGui::BeginTable("large_table", 3, ImGuiTableFlags_ScrollY)) {
    ImGui::TableSetupColumn("ID");
    ImGui::TableSetupColumn("Name");
    ImGui::TableSetupColumn("Value");
    ImGui::TableHeadersRow();
    
    ImGuiListClipper clipper;
    clipper.Begin(10000);  // 10,000 items
    while (clipper.Step()) {
        for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++) {
            ImGui::TableNextRow();
            ImGui::TableNextColumn(); ImGui::Text("%d", row);
            ImGui::TableNextColumn(); ImGui::Text("Item %d", row);
            ImGui::TableNextColumn(); ImGui::Text("%d", row * 10);
        }
    }
    ImGui::EndTable();
}

Best Practices

Always call EndTable() only if BeginTable() returns true.
Use ImGuiTableFlags_SizingStretchProp for responsive tables that adapt to window size.
Call TableSetupColumn() before TableHeadersRow() to define column properties and labels.
Combine ImGuiTableFlags_ScrollY with TableSetupScrollFreeze(0, 1) to keep headers visible while scrolling.

Build docs developers (and LLMs) love