First Grid
The first grid is intentionally a feature-rich example. It shows how a single FdcDataSet definition drives editing, formatting, searching, filtering, summaries, record state, and navigation through one grid surface.
import 'package:flutter_data_components/fdc.dart';
var nextCustomerId = 21;
final customersDataSet = FdcDataSet(
fields: const <FdcFieldDef>[
FdcIntegerField(
name: 'customer_id',
label: 'ID',
isKey: true,
storage: FdcFieldStorage(updateable: false),
),
FdcStringField(
name: 'company_name',
label: 'Company',
size: 120,
required: true,
),
FdcStringField(
name: 'contact_name',
label: 'Contact',
size: 80,
required: true,
),
FdcStringField(name: 'city', label: 'City', size: 60),
FdcStringField(name: 'state', label: 'State', size: 30),
FdcStringField(name: 'industry', label: 'Industry', size: 60),
FdcStringField(name: 'status', label: 'Status', size: 30),
FdcDecimalField(
name: 'credit_limit',
label: 'Credit Limit',
precision: 12,
scale: 2,
minValue: 0,
),
FdcBooleanField(
name: 'active',
label: 'Active',
defaultValue: true,
),
FdcDateField(name: 'registered_at', label: 'Registered'),
],
adapter: FdcMemoryDataAdapter(rows: customers),
onNewRecord: (dataSet) {
dataSet.setFieldValue('customer_id', nextCustomerId++);
dataSet.setFieldValue('company_name', 'New customer');
dataSet.setFieldValue('status', 'Lead');
dataSet.setFieldValue('credit_limit', 5000);
dataSet.setFieldValue('active', true);
dataSet.setFieldValue('registered_at', DateTime.now());
},
);
FdcGrid(
dataSet: customersDataSet,
options: const FdcGridOptions(autoEdit: true),
header: const FdcGridHeader(
filters: FdcGridHeaderFilters(
visible: true,
initiallyVisible: true,
),
),
toolbar: const FdcGridToolbar(
items: <FdcGridItem>[
FdcGridMainMenuButton(),
FdcGridSearchBar(mode: FdcGridSearchBarMode.advanced),
],
),
statusBar: const FdcGridStatusBar(visible: true),
rowIndicator: const FdcGridRowIndicator(
visible: true,
options: FdcGridRowIndicatorOptions(
showRecordStatus: true,
showRowNumbers: true,
showRowSelect: true,
),
),
pinning: const FdcGridColumnPinning(enabled: true),
columnGroups: const <FdcGridColumnGroup>[
FdcGridColumnGroup(id: 'customer', label: 'Customer'),
FdcGridColumnGroup(id: 'location', label: 'Location'),
],
columns: const <FdcGridColumn<dynamic>>[
FdcIntegerColumn<dynamic>(
fieldName: 'customer_id',
width: 96,
readOnly: true,
),
FdcTextColumn<dynamic>(
fieldName: 'company_name',
width: 210,
groupId: 'customer',
),
FdcTextColumn<dynamic>(
fieldName: 'contact_name',
width: 165,
groupId: 'customer',
),
FdcTextColumn<dynamic>(
fieldName: 'city',
width: 135,
groupId: 'location',
),
FdcTextColumn<dynamic>(
fieldName: 'state',
width: 90,
groupId: 'location',
),
FdcTextColumn<dynamic>(fieldName: 'industry', width: 145),
FdcComboColumn<String>(
fieldName: 'status',
width: 110,
options: <FdcOption<String>>[
FdcOption<String>(value: 'Lead', label: 'Lead'),
FdcOption<String>(value: 'Active', label: 'Active'),
FdcOption<String>(value: 'On Hold', label: 'On Hold'),
FdcOption<String>(value: 'Inactive', label: 'Inactive'),
],
),
FdcDecimalColumn<dynamic>(
fieldName: 'credit_limit',
width: 145,
prefixText: r'$ ',
summary: FdcColumnSummary(
aggregate: FdcAggregate.sum,
label: 'Total',
allowAggregateChange: true,
),
),
FdcBooleanColumn<dynamic>(fieldName: 'active', width: 100),
FdcDateColumn<dynamic>(fieldName: 'registered_at', width: 130),
],
);
The Code tab contains the complete dataset schema and grid configuration used by the sample. Only the customers row data is omitted so the important structure remains visible.
What the code builds
The dataset defines the data contract
final customersDataSet = FdcDataSet(
fields: const <FdcFieldDef>[
// typed field definitions
],
adapter: FdcMemoryDataAdapter(rows: customers),
onNewRecord: (dataSet) {
// defaults for new records
},
);
The field list is the shared schema. It defines keys, types, labels, required values, storage rules, numeric precision, defaults, and other data behavior independently of the grid.
FdcMemoryDataAdapter supplies the sample rows. The same dataset-facing model can be used with other adapters without redesigning the grid. onNewRecord centralizes values that should be assigned whenever the grid inserts or appends a record.
Auto-edit creates a fast data-entry workflow
options: const FdcGridOptions(autoEdit: true),
With auto-edit enabled, typing into an editable selected cell can enter editing directly. Combined with keyboard traversal, this makes the grid suitable for keyboard-heavy CRUD and data-entry screens.
Header filters are available immediately
header: const FdcGridHeader(
filters: FdcGridHeaderFilters(
visible: true,
initiallyVisible: true,
),
),
visible enables the header-filter feature. initiallyVisible opens the filter row when the grid first appears, so the sample exposes filtering immediately.
The main menu and search live in the toolbar
toolbar: const FdcGridToolbar(
items: <FdcGridItem>[
FdcGridMainMenuButton(),
FdcGridSearchBar(mode: FdcGridSearchBarMode.advanced),
],
),
The toolbar is composed from ordered items. FdcGridMainMenuButton moves the grid main-menu affordance into the toolbar; the duplicate header menu is hidden automatically. The advanced search bar provides the global search surface for the bound dataset.
Record state is visible around the data viewport
statusBar: const FdcGridStatusBar(visible: true),
rowIndicator: const FdcGridRowIndicator(
visible: true,
options: FdcGridRowIndicatorOptions(
showRecordStatus: true,
showRowNumbers: true,
showRowSelect: true,
),
),
The status bar provides a persistent grid footer. The row indicator adds record-state feedback, row numbers, and row-selection controls without adding artificial dataset fields.
Column groups organize related fields
columnGroups: const <FdcGridColumnGroup>[
FdcGridColumnGroup(id: 'customer', label: 'Customer'),
FdcGridColumnGroup(id: 'location', label: 'Location'),
],
Columns opt into a visual group through groupId. In this sample, company and contact fields appear under Customer, while city and state appear under Location. Grouping changes only the header structure; it does not change the dataset schema or field behavior.
FdcTextColumn<dynamic>(
fieldName: 'city',
groupId: 'location',
),
Pinning and column definitions shape the interaction surface
pinning: const FdcGridColumnPinning(enabled: true),
The sample enables interactive column pinning, but no column starts pinned. Users can choose pinning actions from the grid UI where the column is eligible. Grouped columns remain part of their visual group and are not pinnable while grouped.
Every grid column binds to a dataset field through fieldName. Column classes then add presentation and interaction behavior appropriate to that field: text editing, combo choices, boolean toggles, date editing, numeric formatting, and so on.
The summary belongs to the numeric column
FdcDecimalColumn<dynamic>(
fieldName: 'credit_limit',
prefixText: r'$ ',
summary: FdcColumnSummary(
aggregate: FdcAggregate.sum,
label: 'Total',
allowAggregateChange: true,
),
),
The credit_limit column formats values as currency and requests a sum summary. allowAggregateChange lets the user switch the aggregate interactively from the summary UI.
The important separation remains unchanged: FdcDataSet owns data state and the edit lifecycle, while FdcGrid provides the high-productivity interaction surface.
Next: Using the Grid