Skip to main content

flutterx_table 2.0.0 copy "flutterx_table: ^2.0.0" to clipboard
flutterx_table: ^2.0.0 copied to clipboard

Highly customizable Flutter table with selection, sorting, filtering, actions, column swap, paging and scrolling modules.

flutterx_table #

Highly customizable Flutter table built from composable modules: row selection, sorting and filtering, row actions, column reordering, plus asynchronous paged loading with paging indicators and scroll views.

Installation #

flutter pub add flutterx_table flutterx_live_data
import 'package:flutterx_table/flutterx_table.dart';

Table #

XRawTable renders a heading from the TableColumns and one row per item, with the cells you yield per row. Pass a LiveList as items and the table rebuilds when it changes:

final users = LiveList<User>(source: initialUsers);

AutoScrollView(
  child: XRawTable<User>(
    columns: const [TableColumn(id: 'name', label: 'Name'), TableColumn(id: 'email', label: 'Email')],
    items: users,
    rowDecorator: XRawTable.oddRowDecorator(),
    placeholder: (context) => const Center(child: Text('No users')),
    rowBuilder: (context, row, user) => [Text(user.name), Text(user.email)],
  ),
)

A column may have a heading widget instead of a label, a columnWidth, and the sortable / filterable flags read by the sort and filter module. Column ids are unique.

Modules #

Modules extend the table through modules, applied in list order; the columns they add (selection first, actions last) are not part of your rowBuilder.

modules: [
  TableSelectionModule<User>(keyOf: (user) => user.id, multipleSelection: selection),
  TableSortFilterModule<User>(sortOptions: sort, filterOptions: filter),
  TableActionsModule<User>(actions: [
    TableAction<User>(icon: const Icon(Icons.delete), tooltip: 'Delete', onAction: remove),
  ]),
  ColumnSwapModule<User>(onSwap: moveColumn),
],
  • Selection: multipleSelection (LiveSet<String> of keys) adds a checkbox column; singleSelection (MutableLiveData<String?>) selects one row. onTapBehaviour (TableRowOnTapBehaviour.none, singleSelect, singleSelectToggle, multiSelect) says what a tap on a row does; it defaults to none when onTap is set, otherwise to selecting the row.
  • Sort and filter: sort is a MutableLiveData<SortOptions?> and filter a MutableLiveData<FilterOptions?>. Tapping a sortable heading cycles ascending, descending, none (sortClearable: false goes back to ascending); the filter button opens a text field. The module only edits the options: sort and filter the data yourself, or load it with ContentTableBuilder. SortOptions and FilterOptions have toJson / fromJson.
  • Actions: TableAction is an icon button per row; actionState returns ActionState.enabled, disabled or invisible per item; TableAction.raw takes any cell widget.
  • Column swap: long-press a heading and drag. The table does not reorder itself; move the column in onSwap:
void moveColumn(TableColumn column, int oldIndex, int newIndex) => columns.apply((list) {
  list.insert(newIndex > oldIndex ? newIndex - 1 : newIndex, list.removeAt(oldIndex));
  return true;
});

To write your own module extend TableModule.

Paged data #

ContentTableBuilder loads the items of the current page, reloads when the page, sort or filter change (after updateDelay, kThemeAnimationDuration by default) and shows the paging indicators under the content:

final pageInfo = MutableLiveData(value: const PageInfo.empty(pageSize: 10));
final sort = MutableLiveData<SortOptions?>();
final filter = MutableLiveData<FilterOptions?>();
final tableKey = GlobalKey<ContentTableBuilderState<User>>();

ContentTableBuilder<User>(
  key: tableKey,
  pageInfo: pageInfo,
  sortOptions: sort,
  filterOptions: filter,
  itemsBuilder: (page, filter, sort) => api.users(page, filter, sort),   // FutureOr<PagedList<User>>
  builder: (context, users, loading) => AutoScrollView(child: XRawTable<User>(/* ... */ items: users)),
)

await tableKey.currentState!.refresh();    // reloads the current page even if nothing changed

itemsBuilder returns a PagedList: the items of the page and the PageInfo the server computed, which replaces the requested one. PagedList.fromJson(json, User.fromJson) reads {"pageInfo": {...}, "items": [...]}.

Paging #

PageInfo holds page (zero-based), pageSize, pageCount and itemsCount, and asserts they are consistent. Build it with PageInfo.empty(pageSize:), PageInfo.exactly(itemsCount:) or PageInfo.of(pageSize:, itemsCount:), and derive from it with copyWith.

The indicators read the PageInfo of the enclosing PagingIndicatorLayout, which ContentTableBuilder provides: PagingIndexIndicator (numbered buttons, the default pageIndicator), PagingArrowsIndicator (first / previous / next / last) and RowsPerPageIndicator (rowsPerPageIndicator: null hides it). Outside a builder, place them in a layout:

PagingIndicatorLayout(
  pageInfo: pageInfo,
  pageIndicator: const PagingArrowsIndicator(),
)

Scrolling #

AutoScrollView scrolls its child in both axes with scrollbars; widthBehaviour and heightBehaviour take a SizeBehaviour (matchContainer, intrinsic, none). IntrinsicScrollView scrolls on one axis (scrollDirection) and is as large as its child unless the parent gives less.

Behavior #

  • TableSelectionModule.rowMultipleSelectionColor and rowSingleSelectionColor, like the default of XRawTable.oddRowDecorator, come from the theme when null; pass Colors.transparent to turn the highlight off.
  • Icons in the cells are scaled by the ambient IconTheme size times the cell text size over the theme body text size, so a larger textStyle gives larger icons.
  • onSwap is not called when the drag is cancelled or the heading is dropped at its own position. newIndex follows ReorderableList.onReorder: it is the index before the moved column is removed.
  • PageInfo.copyWith without page and PageInfo.fromJson limit the page to the last valid one instead of failing; an explicit page in copyWith or the constructor must be valid.
  • An error of itemsBuilder without onError is reported to FlutterError.reportError; the page, sort and filter revert to the last loaded ones. With onError, its return value decides whether to revert.
  • refresh() waits for updateDelay, and completes at once if a newer change supersedes it.
  • All the rows are built at every rebuild: there is no virtualization, so page the data.

Claude Code plugin #

The repository ships a plugin with a skill that teaches Claude Code to integrate the library:

/plugin marketplace add https://gitlab.com/dade.sliep/flutterx_table
/plugin install flutterx-table@flutterx-table
4
likes
150
points
163
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Highly customizable Flutter table with selection, sorting, filtering, actions, column swap, paging and scrolling modules.

Homepage

License

BSD-3-Clause (license)

Dependencies

collection, flutter, flutterx_live_data, flutterx_utils

More

Packages that depend on flutterx_table