Skip to main content

Detail Rows

PRO
Pro preview

This feature is part of FD Components Pro, which is documented as a preview and is not publicly available yet. See Editions and Availability.

Detail rows let a grid reveal rich, row-specific content without navigating away from the current data view. The expanded panel can host any Flutter widget tree, including forms, charts, dashboards, child grids, and document previews.

Order reports in detail rows
Loading FDC sample…
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter_data_components_pro/fdc_pro.dart';
import 'package:pdf/pdf.dart';
import 'package:pdfrx/pdfrx.dart';

FdcProGrid(
dataSet: orders,
options: const FdcGridOptions(
readOnly: true,
allowColumnSorting: true,
),
toolbar: const FdcGridToolbar(
items: <FdcGridItem>[
FdcGridSearchBar(
placement: FdcGridItemPlacement.start,
mode: FdcGridSearchBarMode.advanced,
),
],
),
columns: orderColumns,
detailRow: FdcGridDetailRow(
detailHeight: 590,
singleExpanded: true,
padding: const EdgeInsets.all(8),
builder: (context, detailContext) {
final orderId = detailContext.value<int>('order_id')!;
final customer = detailContext.value<String>('customer')!;

return FutureBuilder<Uint8List>(
future: buildOrderReport(
format: PdfPageFormat.a4,
orderId: orderId,
customer: customer,
),
builder: (context, snapshot) {
final bytes = snapshot.data;
if (bytes == null) {
return const Center(child: CircularProgressIndicator());
}

return PdfViewer.data(
Uint8List.fromList(bytes),
sourceName: 'order-$orderId-report.pdf',
);
},
);
},
),
);

The sample keeps order search and column sorting directly available in the grid, while each expanded row renders a generated PDF report for that specific order. The PDF is built with the pdf package and displayed inline with PdfViewer.data from the pdfrx package. The viewer is intentionally presentation-only in this sample, with no print or share action bar.

Basic configuration

Add FdcGridDetailRow to FdcProGrid and provide a builder. The builder receives a stable row context so values can be read from the expanded source row even when it is not the dataset's current record.

FdcProGrid(
dataSet: customers,
detailRow: FdcGridDetailRow(
detailHeight: null,
singleExpanded: true,
builder: (context, detailContext) {
final company = detailContext.value<String>('company') ?? '';
return CustomerDetails(company: company);
},
),
)

Set detailHeight: null to size each panel to its content. Use minHeight and maxHeight to constrain content-sized panels. For embedded viewers, dashboards, and other viewport-oriented content, a fixed detailHeight is usually more appropriate.

Row context

FdcGridDetailRowContext identifies the source row represented by the panel. Read values through the context rather than assuming the expanded row is also the dataset's current record.

builder: (context, detailContext) {
final orderId = detailContext.value<int>('order_id');
final customer = detailContext.value<String>('customer');

return OrderReport(
orderId: orderId!,
customer: customer!,
);
},

The context also exposes row identity and expansion state for advanced scenarios.

Interaction policy

Useful options include:

FdcGridDetailRow(
builder: buildCustomerDetails,
singleExpanded: true,
collapseOnCurrentRowChange: false,
toggleOnRowTap: true,
)

singleExpanded keeps only one detail panel open at a time. toggleOnRowTap allows a regular row tap to expand or collapse the panel after activating the row, while the dedicated expander remains available independently.

Use canExpandRow to suppress expansion for selected rows:

FdcGridDetailRow(
builder: buildOrderDetails,
canExpandRow: (context) {
return context.value<String>('status') != 'Cancelled';
},
)

onExpanded and onCollapsed are notification callbacks fired after the state transition has been applied.

Control detail rows from code

Use the grid controller when page-level commands need to change expansion state:

gridController.expandDetailRow();
gridController.expandDetailRow(rowIndex: 4);

gridController.collapseDetailRow();
gridController.collapseDetailRow(rowIndex: 4);
gridController.collapseAllDetailRows();

When rowIndex is omitted, expand and collapse commands target the current row. The methods return whether the requested expansion state changed.

See Grid Controller for controller lifecycle and the complete command surface.

Rich detail content

A detail row is not limited to simple text. Because the builder returns a regular Flutter widget, the panel can contain stateful controls and complex compositions:

  • generated PDF or document previews,
  • analytics and KPI panels,
  • child grids and master-detail views,
  • forms and workflow actions,
  • charts, maps, and custom visualizations.

For large or expensive detail widgets, initialize work inside the detail widget itself and release owned resources from its dispose lifecycle.