Data Table
Cross-platform extension. iOS 26 surfaces tabular data as grouped lists (
LiqList/ Settings-style sections), not as classic header-plus-body tables — the system has no native equivalent. The closest references are shadcn/ui and forui.dev. liqkit_ui ships this rendered in iOS 26 visual language (Liquid Glass surfaces, San Francisco type, iOS color palette) so it composes cleanly with the rest of the library, but the interaction model itself is web-native rather than iOS-canonical.
LiqDataTable is the iOS 26 simple data table — a header row plus body
rows with hairline separators inside a rounded card. Width is provided
by the parent constraints; columns share that width using the flex
factor on each LiqDataColumn.
The table is intentionally not a full-blown spreadsheet. It does not
sort, paginate, or virtualize the data on its own — the consumer
reorders the rows list in response to onSortChanged and passes the
updated list back in. Sort cycle is none → ascending → descending → none.
Default
// ignore_for_file: file_names // hyphenated name required by snippet manifest conventionimport 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/liqkit_ui.dart';const List<LiqDataColumn> _columns = <LiqDataColumn>[ LiqDataColumn(label: 'Name'), LiqDataColumn(label: 'Role'), LiqDataColumn(label: 'Joined', numeric: true),];const List<LiqDataRow> _rows = <LiqDataRow>[ LiqDataRow(cells: <Widget>[Text('Jane Doe'), Text('Engineer'), Text('2024')]), LiqDataRow(cells: <Widget>[Text('Alex Kim'), Text('Design'), Text('2023')]), LiqDataRow(cells: <Widget>[Text('Sam Park'), Text('PM'), Text('2025')]),];/// Snippet builder consumed by `apps/docs_snippets/lib/src/routes.g.dart`.Widget dataTableDefaultBuilder(BuildContext context) { return SnippetFrame( maxWidth: 480, child: LiqDataTable(columns: _columns, rows: _rows), );}
Sortable
// ignore_for_file: file_names // hyphenated name required by snippet manifest conventionimport 'package:docs_snippets/src/demo.dart';import 'package:docs_snippets/src/snippet_frame.dart';import 'package:flutter/widgets.dart';import 'package:liqkit_ui/liqkit_ui.dart';class _Person { const _Person(this.name, this.role, this.joined); final String name; final String role; final int joined;}const List<_Person> _people = <_Person>[ _Person('Jane Doe', 'Engineer', 2024), _Person('Alex Kim', 'Design', 2023), _Person('Sam Park', 'PM', 2025),];/// Snippet builder consumed by `apps/docs_snippets/lib/src/routes.g.dart`.Widget dataTableSortableBuilder(BuildContext context) { return SnippetFrame( maxWidth: 480, child: LiqDemo<({int? col, LiqSortDirection dir})>( initial: (col: null, dir: LiqSortDirection.none), builder: (state, set) { // Reorder rows in response to the table's sort callback. final sorted = <_Person>[..._people]; if (state.col == 2 && state.dir != LiqSortDirection.none) { sorted.sort((a, b) => a.joined.compareTo(b.joined)); if (state.dir == LiqSortDirection.descending) { final reversed = sorted.reversed.toList(); sorted ..clear() ..addAll(reversed); } } return LiqDataTable( columns: const <LiqDataColumn>[ LiqDataColumn(label: 'Name'), LiqDataColumn(label: 'Role'), LiqDataColumn(label: 'Joined', sortable: true, numeric: true), ], sortColumnIndex: state.col, sortDirection: state.dir, onSortChanged: (col, dir) => set((col: col, dir: dir)), rows: <LiqDataRow>[ for (final p in sorted) LiqDataRow( cells: <Widget>[ Text(p.name), Text(p.role), Text('${p.joined}'), ], ), ], ); }, ), );}