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-zeroouter_sizetoBeginTable()to define the viewport dimensions.ImGuiTableFlags_PreciseWidths— Forces strict adherence to widths set viaTableSetColumnWidth()without automatic adjustments.
The Standard Table Lifecycle
Creating a table follows a strict sequence enforced by the imgui.cpp implementation:
- Call
BeginTable()with a unique ID, column count, and optional flags. - Optionally set explicit column widths using
TableSetColumnWidth()before any row operations. - Define headers using
TableSetupColumn()followed byTableHeadersRow(). - Iterate data rows, calling
TableNextRow()for each new row. - Populate cells using
TableNextColumn()or by explicitly positioning widgets. - 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 forBeginTable,TableNextRow,TableSetColumnWidth, and flag enums (lines approximately 2016-2085 for flags).imgui.cpp— Implements the table rendering pipeline includingBeginTableExandTableUpdateLayout.imgui_internal.h— Defines the internalImGuiTablestruct (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 afterBeginTable()and before any row operations. - Iterate rows using
TableNextRow()and populate cells withTableNextColumn()or direct widget placement. - Configure behavior using flags like
ImGuiTableFlags_Resizable,ImGuiTableFlags_Sortable, andImGuiTableFlags_ScrollY. - Reference implementation in
imgui.cpphandles the complex layout calculations whileimgui.hprovides 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →