Easy Table

  • Ready for a large number of data. Building cells on demand.
  • Focused on Web/Desktop Applications.
  • Bidirectional scroll bars.
  • Sortable.
  • Resizable.
  • Highly customized.
  • Pinned columns.

Usage

Get started

EasyTableModel<Person>? _model;

@override
void initState() {
  super.initState();

  _model = EasyTableModel<Person>(rows: [
    Person('Landon', 19),
    Person('Sari', 22),
    Person('Julian', 37),
    Person('Carey', 39),
    Person('Cadu', 43),
    Person('Delmar', 72)
  ], columns: [
    EasyTableColumn(name: 'Name', stringValue: (row) => row.name),
    EasyTableColumn(name: 'Age', intValue: (row) => row.age)
  ]);
}

@override
Widget build(BuildContext context) {
  return EasyTable<Person>(_model);
}

Columns fit

    _model = EasyTableModel<Person>(rows: rows, columns: [
      EasyTableColumn(name: 'Name', weight: 5, stringValue: (row) => row.name),
      EasyTableColumn(name: 'Age', weight: 1, intValue: (row) => row.age)
    ]);
  EasyTable<Person>(_model, columnsFit: true);

Column style

    _model = EasyTableModel<Person>(rows: rows, columns: [
      EasyTableColumn(name: 'Name', width: 120, stringValue: (row) => row.name),
      EasyTableColumn(
          name: 'Age',
          width: 120,
          intValue: (row) => row.age,
          headerTextStyle: TextStyle(color: Colors.blue[900]!),
          headerAlignment: Alignment.center,
          cellAlignment: Alignment.center,
          cellTextStyle: TextStyle(color: Colors.blue[700]!))
    ]);

Custom cell widget

    _model = EasyTableModel<Person>(rows: rows, columns: [
      EasyTableColumn(name: 'Name', stringValue: (row) => row.name),
      EasyTableColumn(
          name: 'Rate',
          width: 150,
          cellBuilder: (context, row) => StarsWidget(stars: row.stars))
    ]);

Row callbacks

@override
Widget build(BuildContext context) {
  return EasyTable<Person>(_model,
      onRowTap: (person) => _onRowTap(context, person),
      onRowSecondaryTap: (person) => _onRowSecondaryTap(context, person),
      onRowDoubleTap: (person) => _onRowDoubleTap(context, person));
}

void _onRowTap(BuildContext context, Person person) {
  ...
}

void _onRowSecondaryTap(BuildContext context, Person person) {
  ...
}

void _onRowDoubleTap(BuildContext context, Person person) {
  ...
}

Pinned column

    _model = EasyTableModel(rows: persons, columns: [
      EasyTableColumn(
          pinned: true,
          width: 30,
          cellBuilder: (BuildContext context, Person row) {
            return InkWell(
                child: const Icon(Icons.edit, size: 16),
                onTap: () => _onEdit(row));
          }),
      EasyTableColumn(name: 'Name', width: 120, stringValue: (row) => row.name),
      EasyTableColumn(name: 'Age', width: 120, intValue: (row) => row.age)
    ]);

Infinite scroll

  final UniqueKey _tableKey = UniqueKey();
  EasyTableModel<String>? _model;
  bool _loading = false;

  @override
  void initState() {
    super.initState();
    List<String> rows = List.generate(30, (index) => 'value $index');
    _model = EasyTableModel<String>(
        rows: rows,
        columns: [EasyTableColumn(name: 'Value', stringValue: (row) => row)]);
  }

  @override
  Widget build(BuildContext context) {
    EasyTable table = EasyTable<String>(_model,
        key: _tableKey, onLastVisibleRowListener: _onLastVisibleRowListener);

    List<Widget> children = [Positioned.fill(key: _tableKey, child: table)];

    if (_loading) {
      children.add(const Positioned(
          child: LoadingWidget(), left: 0, right: 0, bottom: 0));
    }
    return Stack(children: children);
  }

  void _onLastVisibleRowListener(int lastVisibleRowIndex) {
    if (!_loading && lastVisibleRowIndex == _model!.visibleRowsLength - 1) {
      setState(() {
        _loading = true;
      });
      Future.delayed(const Duration(seconds: 2), () {
        setState(() {
          _loading = false;
          List<String> newValues = List.generate(
              30, (index) => 'value ${_model!.visibleRowsLength + index}');
          _model!.addRows(newValues);
        });
      });
    }
  }

Theme

Scrollbar

Horizontal scrollbar only when needed

EasyTableTheme(
        child: EasyTable<Person>(_model),
        data: const EasyTableThemeData(
            scrollbar:
                TableScrollbarThemeData(horizontalOnlyWhenNeeded: true)));

A warning is being displayed in the console due to a bug in Flutter: https://github.com/flutter/flutter/issues/103939. The error happens when the horizontal scrollbar is hidden after being visible. The following MR should fix the issue: https://github.com/flutter/flutter/pull/103948

Cell

Null value color

  _model = EasyTableModel<Person>(rows: [
    Person('Landon', '+321 321-432-543'),
    Person('Sari', '+123 456-789-012'),
    Person('Julian', null),
    Person('Carey', '+111 222-333-444'),
    Person('Cadu', null),
    Person('Delmar', '+22 222-222-222')
  ], columns: [
    EasyTableColumn(name: 'Name', width: 120, stringValue: (row) => row.name),
    EasyTableColumn(
        name: 'Mobile', width: 150, stringValue: (row) => row.mobile)
  ]);
  EasyTableTheme(
      child: EasyTable<Person>(_model),
      data: EasyTableThemeData(
          cell:
              CellThemeData(nullValueColor: ((rowIndex) => Colors.grey[300]))));

Divider

Divider color and thickness

EasyTableTheme(
        child: EasyTable<Person>(_model),
        data: const EasyTableThemeData(
            columnDividerThickness: 2,
            columnDividerColor: Colors.blue,
            row:
                RowThemeData(dividerThickness: 2, dividerColor: Colors.green)));

TODO

  • Easiest way to create loading indicator for infinite scroll
  • Collapsed rows
  • Header grouping
  • Row selection
  • Cell edition?
  • Column reorder
  • Pinned column on right?
  • Filter
  • And everything else, the sky is the limit

Support this project

Bitcoin

bc1qhqy84y45gya58gtfkvrvass38k4mcyqnav803h

Ethereum (ERC-20) or Binance Smart Chain (BEP-20)

0x9eB815FD4c88A53322304143A9Aa8733D3369985

Solana

7vp45LoQXtLYFXXKx8wQGnzYmhcnKo1TmfqUgMX45Ad8

Helium

13A2fDqoApT9VnoxFjHWcy8kPQgVFiVnzps32MRAdpTzvs3rq68

Libraries

easy_table