Skip to main content

Examples

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.
NeoTableColumnAlignment
default:".left"
Where the header label and cell content sit in the column. right places the sort icon before the label so the label’s trailing edge lines up with the cell text. A cell that expands to the full column width, such as a SizedBox with width: double.infinity, fills the cell and the alignment is not visible.

Sorting

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

Reordering / Visibility

bool
default:"true"
Whether this column’s header 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.

NeoTableColumnAlignment

Horizontal placement of a column’s header label and cell content.
  • left: Align to the start of the column. Default.
  • center: Center the label and cell content in the column.
  • right: Align to the end of the column. The sort icon sits before the label.

Best Practices

  • Use alignment: .right for numbers so the header and the values share an edge.
  • Turn sorting off while rows are being reordered. A live sort and a manual order disagree.

Behavior

  • In debug mode the table asserts that row ids are unique and that every visible column id has a cell.
  • A sortable column cycles descending, then ascending, then unsorted. The column in defaultSortState cycles descending, then ascending, then descending, and does not clear.
  • The table needs a bounded width.
  • NeoTable.scrollToRow needs the scrollController you pass to the table.
Last modified on September 30, 2026