Skip to main content

Examples

Simple data table with column headers.

Properties

Required

List<NeoTableColumn>
required
The column definitions that determine the table’s structure and headers.
List<NeoTableRow>
required
The data rows to display. Each row’s cells map must include a widget for every visible column ID.

Content

ValueChanged<String>
Called when a row is tapped. Receives the row ID.
ValueChanged<({String rowId, bool isHovered})>
Called when a row’s hover state changes. Receives the row ID and hover status.
String
The ID of the currently active row. The active row receives distinct highlight styling.
Widget
Widget to display when rows is empty. Falls back to an empty table body if not provided.

Layout

double
default:"48"
Fixed height for all rows in logical pixels.
double
default:"40"
Height of the sticky column-header row in logical pixels.
bool
default:"false"
Whether to show a border around the entire table.
bool
default:"false"
Whether to show horizontal divider lines between rows.
bool
default:"false"
Whether to show vertical divider lines between columns.
ScrollController
Scroll controller for the table body. Required when using NeoTable.scrollToRow. An internal controller is used when not provided.
Set<String>
Set of column IDs to hide. The columns remain in columns so their cells are still defined in rows — they are simply not rendered.

Sorting

NeoTableSortState
The current sort state (column ID + direction). null means unsorted.
NeoTableSortState
The sort state to fall back to when no explicit sortState is set. The default-sort column cannot be fully unsorted — it cycles between ascending and descending.
ValueChanged<NeoTableSortState?>
Called when the user clicks a sortable column header. Receives the new NeoTableSortState, or null when returning to the unsorted state.

Selection

bool
default:"false"
Whether rows can be selected with checkboxes. When true, onSelectionChanged must be provided.
Set<String>
The currently selected row IDs.
ValueChanged<Set<String>>
Called when the selection changes. Required when isSelectable is true.

Reordering

bool
default:"false"
Whether rows can be reordered by dragging. When true, onRowReorder must be provided.
Function(String rowId, int oldIndex, int newIndex)
Called when the user drops a row into a new position. Required when isRowReorderable is true.
bool
default:"false"
Whether columns can be reordered by dragging their headers. When true, onColumnReorder must be provided.
Function(String columnId, int oldIndex, int newIndex)
Called when the user drops a column header into a new position. Required when isColumnReorderable is true.

State

bool
default:"false"
Displays a loading indicator over the table body and disables interaction.

Static Helpers

NeoTable.scrollToRow()

Animates the table body scroll so the given row is aligned to the top of the viewport (below the fixed header).
ScrollController
required
The same ScrollController passed to the table’s scrollController prop.
List<NeoTableRow>
required
The current row list — must match the table’s rows prop.
String
required
The ID of the row to scroll to.
double
required
Must match the table’s fixedRowHeight prop.
bool
default:"false"
Must match the table’s showRowDividers prop so the scroll offset accounts for divider height.

Column Properties

Required

String
required
A unique identifier for the column.
String
required
The display text for the column header.

Layout

int
default:"1"
Relative width of the column. Higher values take proportionally more space.
double
Minimum width in logical pixels. The column will not shrink below this value regardless of flex.

Sorting

bool
default:"false"
Whether clicking this column’s header triggers NeoTable.onSortChanged.

Reordering / Visibility

bool
default:"true"
Whether this column can be dragged when NeoTable.isColumnReorderable is true.
bool
default:"true"
Whether this column can be included in NeoTable.hiddenColumnIds.

Row Properties

Required

String
required
A unique identifier for the row.
Map<String, Widget>
required
A map from column ID to the cell widget. Every visible column must have a corresponding entry.

Enums

NeoTableSortDirection

Sort direction for a column. The absence of a sort state (i.e. null on the table) represents the unsorted state — there is no none value.
  • ascending: Sort from lowest to highest.
  • descending: Sort from highest to lowest.

Best Practices

  • Cell map keys: Use the exact column id strings as cells map keys. The table asserts in debug mode if any visible column’s ID is missing from a row’s cells.
  • Width constraints: Always provide a bounded width constraint (via Expanded, SizedBox, etc.) so the table’s flex layout has a finite extent to divide.
  • Scroll to row: Pass a scrollController whenever you plan to call NeoTable.scrollToRow.
  • Reordering and sorting: Enabling both isRowReorderable and a live sortState at the same time can produce confusing UX — the reordered position conflicts with the sorted order. Consider disabling sorting while reordering is active.

Integration Notes

  • The table validates that all row IDs are unique and that every visible column has a matching cell in each row, both via debug-mode assertions.
  • Sort cycling for a sortable column: descending → ascending → null (unsorted). When a defaultSortState is set for the column, the cycle is descending → ascending only.
Last modified on May 10, 2026