How to Use Dear ImGui Tables API: BeginTable, TableNextRow, and TableSetColumnWidth

Dear ImGui's Tables API creates grid-based layouts using BeginTable() to initialize the table, TableNextRow() to advance through rows, and TableSetColumnWidth() to control column sizing, all implemented in the ocornut/imgui repository.

The Dear ImGui Tables API provides a high-performance way to render tabular data with built-in support for sorting, column resizing, and scrolling. According to the ocornut/imgui source code, the public API resides in imgui.h while the implementation logic and internal ImGuiTable struct (defined around line 3068 in imgui_internal.h) handle the complex layout calculations.

Core Tables API Functions

The Tables API in imgui.h exposes several key functions that manage the table lifecycle:

BeginTable() — bool BeginTable(const char* str_id, int columns, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0,0), float inner_width = 0.0f)

Creates a table with the specified number of columns. Returns false if the table is clipped, allowing early-out optimization. This function initializes the internal table state maintained in imgui.cpp.

EndTable() — void EndTable()

Closes the table context. Must only be called if BeginTable() returned true.

TableNextRow() — bool TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f)

Advances to a new row. Returns false only when the row is completely outside the visible area.

TableNextColumn() — bool TableNextColumn()

Moves to the next column in the current row. Returns false when the column is out of view.

TableSetColumnWidth() — void TableSetColumnWidth(int column_n, float width)

Forces column column_n to the exact width in pixels. According to the implementation in imgui.cpp, this must be called after BeginTable() but before any TableNextRow() that would use the column.

TableGetColumnCount() — int TableGetColumnCount()

Returns the column count passed to BeginTable().

TableGetSortSpecs() — ImGuiTableSortSpecs* TableGetSortSpecs()

Retrieves sorting specifications when ImGuiTableFlags_Sortable is enabled.

Table Flags and Configuration

The Tables API supports extensive configuration through flags defined in imgui.h (approximately lines 2016-2085). Key flags include:

  • ImGuiTableFlags_Resizable — Allows users to drag column borders to resize columns.
  • ImGuiTableFlags_Sortable — Makes column headers clickable for data sorting.
  • ImGuiTableFlags_NoBordersInBody — Renders the table body without internal borders.
  • ImGuiTableFlags_ScrollX / ImGuiTableFlags_ScrollY — Enables horizontal or vertical scrolling. When using scrolling, you must provide a non-zero outer_size to BeginTable() to define the viewport dimensions.
  • ImGuiTableFlags_PreciseWidths — Forces strict adherence to widths set via TableSetColumnWidth() without automatic adjustments.

The Standard Table Lifecycle

Creating a table follows a strict sequence enforced by the imgui.cpp implementation:

  1. Call BeginTable() with a unique ID, column count, and optional flags.
  2. Optionally set explicit column widths using TableSetColumnWidth() before any row operations.
  3. Define headers using TableSetupColumn() followed by TableHeadersRow().
  4. Iterate data rows, calling TableNextRow() for each new row.
  5. Populate cells using TableNextColumn() or by explicitly positioning widgets.
  6. Call EndTable() to finalize rendering.

Practical Code Examples

Fixed-Width Table Implementation

This example demonstrates explicit column width control using TableSetColumnWidth():

if (ImGui::BeginTable("FixedWidth", 2,
        ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody, ImVec2(0,0))) {
    // Set widths before any row operations
    ImGui::TableSetColumnWidth(0, 200.0f);  // First column: 200px
    ImGui::TableSetColumnWidth(1, 100.0f);  // Second column: 100px

    ImGui::TableNextRow();
    ImGui::TableNextColumn(); ImGui::Text("ID");
    ImGui::TableNextColumn(); ImGui::Text("Value");

    for (int i = 0; i < 5; ++i) {
        ImGui::TableNextRow();
        ImGui::TableNextColumn(); ImGui::Text("%d", i);
        ImGui::TableNextColumn(); ImGui::Text("Item %d", i);
    }
    ImGui::EndTable();
}

Scrollable Table with Sortable Headers

For tables requiring scrolling and sorting capabilities:

ImVec2 outer_size = ImVec2(0, 300);  // 300px height viewport
if (ImGui::BeginTable("Scrollable", 4,
        ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable |
        ImGuiTableFlags_ScrollY | ImGuiTableFlags_Sortable, outer_size)) {
    
    // Configure columns with flags
    ImGui::TableSetupColumn("File");
    ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_AlignRight);
    ImGui::TableSetupColumn("Date");
    ImGui::TableSetupColumn("Owner");
    ImGui::TableHeadersRow();  // Renders the header row

    for (const auto& file : files) {
        ImGui::TableNextRow();
        ImGui::TableNextColumn(); ImGui::TextUnformatted(file.name.c_str());
        ImGui::TableNextColumn(); ImGui::Text("%llu", file.size);
        ImGui::TableNextColumn(); ImGui::Text("%s", file.date.c_str());
        ImGui::TableNextColumn(); ImGui::Text("%s", file.owner.c_str());
    }
    ImGui::EndTable();
}

Dynamic Column Width Adjustment

This pattern shows runtime width modification using TableSetColumnWidth():

static float col0_width = 120.0f;
if (ImGui::BeginTable("DynamicWidth", 2,
        ImGuiTableFlags_Borders | ImGuiTableFlags_PreciseWidths)) {
    
    // Apply width before row creation
    ImGui::TableSetColumnWidth(0, col0_width);
    
    ImGui::TableNextRow();
    ImGui::TableNextColumn(); 
    ImGui::Text("Adjustable column");
    
    ImGui::TableNextColumn(); 
    ImGui::SliderFloat("Width##col0", &col0_width, 80.0f, 300.0f);
    
    ImGui::EndTable();
}

Source Code Architecture

Understanding the implementation requires examining these specific files in the ocornut/imgui repository:

  • imgui.h — Contains public declarations for BeginTable, TableNextRow, TableSetColumnWidth, and flag enums (lines approximately 2016-2085 for flags).
  • imgui.cpp — Implements the table rendering pipeline including BeginTableEx and TableUpdateLayout.
  • imgui_internal.h — Defines the internal ImGuiTable struct (around line 3068) and private helper functions used by the public API.

Summary

  • Initialize tables with BeginTable() using a unique string ID and column count; check the boolean return value before proceeding.
  • Control layout by calling TableSetColumnWidth() immediately after BeginTable() and before any row operations.
  • Iterate rows using TableNextRow() and populate cells with TableNextColumn() or direct widget placement.
  • Configure behavior using flags like ImGuiTableFlags_Resizable, ImGuiTableFlags_Sortable, and ImGuiTableFlags_ScrollY.
  • Reference implementation in imgui.cpp handles the complex layout calculations while imgui.h provides the stable public interface.

Frequently Asked Questions

When should I call TableSetColumnWidth in the Dear ImGui Tables API?

You must call TableSetColumnWidth() after BeginTable() returns true but before calling TableNextRow() or TableNextColumn() that would use the target column. According to the implementation in imgui.cpp, setting widths after rows have started processing has no effect on the current frame's layout.

What is the difference between TableNextRow and TableNextColumn?

TableNextRow() explicitly starts a new row in the table grid, while TableNextColumn() advances to the next column in the current row or automatically starts a new row if the current row is full. For single-column-per-row iteration, TableNextColumn() serves as a convenient shortcut that handles both operations.

How do I enable scrolling in Dear ImGui tables?

To enable scrolling, pass ImGuiTableFlags_ScrollX or ImGuiTableFlags_ScrollY to BeginTable(), and crucially, provide a non-zero outer_size parameter (typically ImVec2(width, height)). If outer_size remains zero, the table expands to fit its contents and scrolling never activates.

Can I use TableSetColumnWidth with resizable tables?

Yes, but with caveats. When ImGuiTableFlags_Resizable is active, user interactions can override your programmatic widths. To enforce strict widths, combine TableSetColumnWidth() with ImGuiTableFlags_PreciseWidths, though this prevents user resizing. Otherwise, call TableSetColumnWidth() each frame to maintain your desired sizes while allowing user adjustments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →