How to Use Dear ImGui Tables API (BeginTable) for Complex Layouts
Dear ImGui's Tables API provides a modern, flexible grid system through BeginTable() and EndTable(), replacing the legacy Columns API with support for scrolling, sorting, nested tables, and per-cell formatting.
The Dear ImGui Tables API (available in the ocornut/imgui repository) offers a robust framework for creating data grids and complex widget layouts. Introduced to supersede the older Columns API, this system handles automatic row/column management, horizontal scrolling, and dynamic sizing through declarative flags and helper functions declared in imgui.h and implemented in imgui_tables.cpp.
Core Tables API Workflow
Creating a table requires a strict lifecycle: initialization, column setup, row population, and termination.
Initializing with BeginTable
Call BeginTable() to instantiate a new table context. This function accepts an identifier, column count, optional flags for borders and scrolling, and sizing constraints. The declaration in imgui.h【https://github.com/ocornut/imgui/blob/master/imgui.h#L882-L909】 shows it returns a boolean indicating visibility—always wrap table content in an if block to avoid processing clipped elements.
if (ImGui::BeginTable("MyTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
// Column setup and row data here
ImGui::EndTable();
}
Configuring Columns with TableSetupColumn
Before populating data, declare column properties using TableSetupColumn(). This function accepts flags like ImGuiTableColumnFlags_WidthFixed or ImGuiTableColumnFlags_WidthStretch to control sizing behavior, as defined in the ImGuiTableColumnFlags enum【https://github.com/ocornut/imgui/blob/master/imgui.h#L2043】.
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 50.0f);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow(); // Creates header row from setup calls
Populating Rows and Cells
Use TableNextRow() to advance to a new row, then TableNextColumn() to iterate through cells sequentially. For random access, TableSetColumnIndex() allows jumping to specific columns. The implementation in imgui_tables.cpp handles automatic row wrapping when column limits are reached.
Implementing Complex Layout Patterns
Fixed versus Stretch Column Sizing
Control column behavior through flags passed to TableSetupColumn(). Fixed width columns maintain absolute pixel sizes, while stretch columns distribute available space proportionally.
ImGui::BeginTable("SizingDemo", 3, ImGuiTableFlags_SizingStretchSame);
ImGui::TableSetupColumn("Fixed", ImGuiTableColumnFlags_WidthFixed, 100.0f);
ImGui::TableSetupColumn("Stretch1", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Stretch2", ImGuiTableColumnFlags_WidthStretch);
Nested Tables for Hierarchical Data
The Tables API supports recursion because each BeginTable() creates an isolated child window. You can embed tables within table cells to create master-detail views or complex grid hierarchies.
if (ImGui::BeginTable("Outer", 2, ImGuiTableFlags_Borders)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Summary Data");
ImGui::TableNextColumn();
if (ImGui::BeginTable("Inner", 3, ImGuiTableFlags_Borders)) {
// Inner table content
ImGui::EndTable();
}
ImGui::EndTable();
}
Column Spanning and Cell Formatting
To span a cell across multiple columns, advance to the starting column with TableSetColumnIndex(), render your content, and skip subsequent TableNextColumn() calls for the spanned columns. Use TableSetBgColor() to apply background colors to specific cells (ImGuiTableBgTarget_CellBg) or entire rows (ImGuiTableBgTarget_RowBg0).
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Spans two columns");
// Skip column 1 to create span effect
ImGui::TableSetColumnIndex(2);
ImGui::Text("Third column");
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, IM_COL32(40, 40, 40, 255));
Frozen Headers and Scrolling
For large datasets, call TableSetupScrollFreeze(columns, rows) to lock headers in place during vertical or horizontal scrolling. This creates Excel-like frozen panes. Combine with ImGuiTableFlags_ScrollX or ImGuiTableFlags_ScrollY to enable scrollable containers.
ImGui::BeginTable("Scrollable", 4, ImGuiTableFlags_ScrollX | ImGuiTableFlags_Borders);
ImGui::TableSetupScrollFreeze(1, 1); // Freeze first column and header row
Practical Implementation Examples
Basic Data Grid with Fixed Widths
if (ImGui::BeginTable("SimpleTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Score", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableHeadersRow();
for (int i = 0; i < 5; ++i) {
ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::Text("%d", i);
ImGui::TableNextColumn(); ImGui::Text("Player %d", i);
ImGui::TableNextColumn(); ImGui::Text("%d", rand() % 100);
}
ImGui::EndTable();
}
Stretch Columns with Horizontal Scrolling
ImGui::BeginTable("StretchTable", 4,
ImGuiTableFlags_Borders |
ImGuiTableFlags_ScrollX |
ImGuiTableFlags_SizingStretchSame,
ImVec2(0.0f, 0.0f), 0.0f);
{
ImGui::TableSetupColumn("A");
ImGui::TableSetupColumn("B");
ImGui::TableSetupColumn("C");
ImGui::TableSetupColumn("D");
ImGui::TableHeadersRow();
for (int row = 0; row < 10; ++row) {
ImGui::TableNextRow();
for (int col = 0; col < 4; ++col) {
ImGui::TableNextColumn();
ImGui::Text("R%dC%d", row, col);
}
}
}
ImGui::EndTable();
Advanced Layout with Row Spanning and Colors
if (ImGui::BeginTable("ComplexLayout", 3, ImGuiTableFlags_Borders)) {
ImGui::TableSetupColumn("Name");
ImGui::TableSetupColumn("Description");
ImGui::TableSetupColumn("Value");
ImGui::TableHeadersRow();
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Item A");
ImGui::TableSetColumnIndex(1);
ImGui::TextUnformatted("This text spans across the description and value columns visually");
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, IM_COL32(30, 30, 160, 255));
ImGui::EndTable();
}
Key Source Files and Architecture
Understanding the implementation requires examining three primary files in the ocornut/imgui repository:
imgui.h【https://github.com/ocornut/imgui/blob/master/imgui.h#L882-L909】: Contains public API declarations includingBeginTable(),EndTable(),TableSetupColumn(), and theImGuiTableFlags/ImGuiTableColumnFlagsenums.imgui_tables.cpp: Houses the complete table layout engine, row/column iteration logic, and rendering implementation.imgui_internal.h【https://github.com/ocornut/imgui/blob/master/imgui_internal.h#L3068-L3177】: Defines internal structuresImGuiTableandImGuiTableColumnused by the layout engine to manage state, clipping, and sizing calculations.
Summary
- Always guard table content with the boolean returned by
BeginTable()to skip rendering when the table is off-screen. - Configure columns upfront using
TableSetupColumn()with specific flags (WidthFixed,WidthStretch,NoResize) to control layout behavior. - Support complex layouts through nested tables, column spanning (by skipping
TableNextColumn()calls), and background color customization viaTableSetBgColor(). - Enable scrolling and freezing with
TableSetupScrollFreeze()and table flags to handle large datasets efficiently. - Reference the source in
imgui_tables.cppandimgui.hfor advanced usage patterns and performance optimizations.
Frequently Asked Questions
What is the difference between Dear ImGui Tables API and the old Columns API?
The Tables API (BeginTable/EndTable) is a complete rewrite that provides proper horizontal scrolling, per-column sizing policies, sorting capabilities, and frozen rows/columns. The old Columns API (ImGui::Columns) lacked these features and is considered deprecated; Tables handle layout calculations in imgui_tables.cpp rather than the general window layout code.
How do I make columns resizable or fixed width in BeginTable?
Pass specific flags to TableSetupColumn(): use ImGuiTableColumnFlags_WidthFixed with an explicit pixel width to prevent resizing, or ImGuiTableColumnFlags_WidthStretch with a weight parameter to allow dynamic resizing. The ImGuiTableFlags_Resizable flag on the table itself enables interactive resizing via drag handles.
Can I nest tables inside other tables using BeginTable?
Yes, you can call BeginTable() inside a table cell (after TableNextColumn()). Each table creates its own child window context with independent scrolling and clipping, as managed by the ImGuiTable structures in imgui_internal.h. This allows for complex hierarchical layouts without coordinate conflicts.
How do I freeze header rows when scrolling in Dear ImGui tables?
Call TableSetupScrollFreeze(0, 1) after BeginTable() to freeze the first row (typically headers), or TableSetupScrollFreeze(1, 1) to freeze both the first column and first row. This locks the specified rows/columns in place while the rest of the table scrolls, implemented through clipping rect calculations in imgui_tables.cpp.
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 →