TableAppi
A powerful and flexible table widget for displaying structured data with support for sorting, filtering, pagination, and custom cell rendering.
Features
- Dynamic Data Display: Display data from various sources with automatic updates
- Sorting: Click column headers to sort data ascending/descending
- Filtering: Built-in search and filter capabilities
- Pagination: Handle large datasets with pagination controls
- Custom Cell Rendering: Customize how individual cells are displayed
- Row Selection: Single or multiple row selection support
- Responsive Design: Adapts to different screen sizes
- Loading States: Built-in loading indicators for async data
Usage
Basic Usage
TableAppi(
columns: [
TableColumn(key: 'name', title: 'Name'),
TableColumn(key: 'age', title: 'Age'),
TableColumn(key: 'email', title: 'Email'),
],
data: [
{'name': 'John Doe', 'age': 30, 'email': 'john@example.com'},
{'name': 'Jane Smith', 'age': 25, 'email': 'jane@example.com'},
],
)
Advanced Usage
TableAppi(
columns: tableColumns,
data: tableData,
isLoading: _isLoading,
enableSorting: true,
enableFiltering: true,
enablePagination: true,
pageSize: 10,
onRowTap: (rowData) => _handleRowTap(rowData),
onSelectionChanged: (selectedRows) => _handleSelection(selectedRows),
customCellBuilder: (column, value, rowData) => _buildCustomCell(column, value, rowData),
)
Parameters
Name | Type | Description | Default |
---|---|---|---|
columns | List<TableColumn> | Required. Column definitions for the table | - |
data | List<Map<String, dynamic>> | Required. Data to display in the table | - |
isLoading | bool? | Whether to show loading indicator | false |
enableSorting | bool? | Enable column sorting | true |
enableFiltering | bool? | Enable data filtering | true |
enablePagination | bool? | Enable pagination | false |
pageSize | int? | Number of rows per page | 10 |
currentPage | int? | Current page number (0-indexed) | 0 |
onRowTap | Function(Map<String, dynamic>)? | Callback when a row is tapped | null |
onSelectionChanged | Function(List<Map<String, dynamic>>)? | Callback when selection changes | null |
customCellBuilder | Widget Function(TableColumn, dynamic, Map<String, dynamic>)? | Custom cell builder | null |
headerStyle | TextStyle? | Style for header text | Theme dependent |
cellStyle | TextStyle? | Style for cell text | Theme dependent |
headerBackgroundColor | Color? | Background color for header | Colors.grey.shade100 |
alternateRowColor | Color? | Background color for alternate rows | Colors.grey.shade50 |
borderColor | Color? | Color of table borders | Colors.grey.shade300 |
selectedRowColor | Color? | Background color for selected rows | Colors.blue.shade100 |
hoverColor | Color? | Color when hovering over rows | Colors.grey.shade200 |
multiSelect | bool? | Allow multiple row selection | false |
showCheckboxes | bool? | Show selection checkboxes | false |
emptyMessage | String? | Message to show when no data | 'No data available' |
searchPlaceholder | String? | Placeholder text for search field | 'Search...' |
TableColumn Model
class TableColumn {
final String key;
final String title;
final bool sortable;
final bool filterable;
final double? width;
final TextAlign? alignment;
final Widget Function(dynamic value, Map<String, dynamic> rowData)? cellBuilder;
TableColumn({
required this.key,
required this.title,
this.sortable = true,
this.filterable = true,
this.width,
this.alignment = TextAlign.left,
this.cellBuilder,
});
}
Best Practices
- Performance: Use pagination for large datasets (>100 rows)
- Column Width: Set appropriate widths for columns to prevent overflow
- Custom Cells: Use custom cell builders for complex data types
- Loading States: Always show loading indicators for async operations
- Empty States: Provide meaningful messages when no data is available
- Accessibility: Ensure proper semantic labels for screen readers
- Responsive: Consider horizontal scrolling for tables with many columns
Examples
Simple Data Table
TableAppi(
columns: [
TableColumn(key: 'id', title: 'ID', width: 60),
TableColumn(key: 'name', title: 'Product Name'),
TableColumn(key: 'price', title: 'Price', alignment: TextAlign.right),
TableColumn(key: 'stock', title: 'Stock', alignment: TextAlign.center),
],
data: products,
)
Table with Custom Cells
TableAppi(
columns: [
TableColumn(key: 'avatar', title: 'Avatar', width: 80),
TableColumn(key: 'name', title: 'Name'),
TableColumn(key: 'status', title: 'Status'),
TableColumn(key: 'actions', title: 'Actions', sortable: false),
],
data: users,
customCellBuilder: (column, value, rowData) {
switch (column.key) {
case 'avatar':
return CircleAvatar(
backgroundImage: NetworkImage(value),
radius: 20,
);
case 'status':
return Chip(
label: Text(value),
backgroundColor: value == 'Active' ? Colors.green : Colors.red,
);
case 'actions':
return Row(
children: [
IconButton(
icon: Icon(Icons.edit),
onPressed: () => _editUser(rowData),
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () => _deleteUser(rowData),
),
],
);
default:
return Text(value.toString());
}
},
)
Paginated Table with Selection
TableAppi(
columns: tableColumns,
data: currentPageData,
enablePagination: true,
pageSize: 20,
currentPage: _currentPage,
multiSelect: true,
showCheckboxes: true,
onSelectionChanged: (selectedRows) {
setState(() {
_selectedItems = selectedRows;
});
},
onPageChanged: (page) {
setState(() {
_currentPage = page;
_loadPageData(page);
});
},
)
Filterable and Sortable Table
TableAppi(
columns: [
TableColumn(key: 'date', title: 'Date', sortable: true),
TableColumn(key: 'transaction', title: 'Transaction', filterable: true),
TableColumn(key: 'amount', title: 'Amount', sortable: true, alignment: TextAlign.right),
],
data: transactions,
enableSorting: true,
enableFiltering: true,
onSortChanged: (column, ascending) {
_sortData(column, ascending);
},
onFilterChanged: (filters) {
_filterData(filters);
},
)