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

> Master Dear ImGui Tables API with BeginTable, TableNextRow, and TableSetColumnWidth. Learn to create efficient grid layouts in your C++ applications using this powerful feature.

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

---

**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`](https://github.com/ocornut/imgui/blob/main/imgui.h) while the implementation logic and internal `ImGuiTable` struct (defined around line 3068 in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)) handle the complex layout calculations.

## Core Tables API Functions

The Tables API in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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()`:

```cpp
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:

```cpp
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()`:

```cpp
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`](https://github.com/ocornut/imgui/blob/main/imgui.h)** — Contains public declarations for `BeginTable`, `TableNextRow`, `TableSetColumnWidth`, and flag enums (lines approximately 2016-2085 for flags).
- **[`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)** — Implements the table rendering pipeline including `BeginTableEx` and `TableUpdateLayout`.
- **[`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) handles the complex layout calculations while [`imgui.h`](https://github.com/ocornut/imgui/blob/main/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`](https://github.com/ocornut/imgui/blob/main/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.