CxJS

Grid

import { Grid } from 'cx/widgets'; Copied

The Grid widget displays tabular data with features like fixed headers, single and multiple selection modes, sorting, filtering, grouping, aggregation, rich cell content, tree columns, and more.

<div controller={PageController}>
  <Grid
    records={m.records}
    style="height: 400px"
    scrollable
    columns={[
      { header: "Name", field: "fullName", sortable: true },
      { header: "Continent", field: "continent", sortable: true },
      { header: "Browser", field: "browser", sortable: true },
      { header: "OS", field: "os", sortable: true },
      {
        header: "Visits",
        field: "visits",
        sortable: true,
        align: "right",
      },
    ]}
    selection={{
      type: KeySelection,
      bind: m.selection,
      keyField: "id",
      multiple: true,
    }}
  />
</div>
NameContinentBrowserOSVisits
John DoeEuropeChromeWindows11
Jane SmithNorth AmericaFirefoxmacOS37
Bob WilsonAsiaSafariLinux12
Alice BrownAfricaEdgeiOS99
Charlie DavisAustraliaChromeAndroid28
John DoeEuropeFirefoxWindows54
Jane SmithNorth AmericaSafarimacOS81
Bob WilsonAsiaEdgeLinux84
Alice BrownAfricaChromeiOS53
Charlie DavisAustraliaFirefoxAndroid59
John DoeEuropeSafariWindows62
Jane SmithNorth AmericaEdgemacOS48
Bob WilsonAsiaChromeLinux89
Alice BrownAfricaFirefoxiOS17
Charlie DavisAustraliaSafariAndroid55
John DoeEuropeEdgeWindows93
Jane SmithNorth AmericaChromemacOS74
Bob WilsonAsiaFirefoxLinux93
Alice BrownAfricaSafariiOS44
Charlie DavisAustraliaEdgeAndroid77

Click on column headers to sort. Hold Ctrl (or Cmd on macOS) and click to select multiple rows.

Columns

Columns define what data is displayed and how. The simplest column configuration uses the field property to display a record property:

columns={[
  { header: "Name", field: "fullName" },
  { header: "Age", field: "age", align: "right" }
]}

For custom cell content, use the children property to render any widget inside the cell. The current record is available via $record:

columns={[
  {
    header: "Name",
    field: "fullName",
    children: <strong text={m.$record.fullName} />
  },
  {
    header: "Actions",
    children: (
      <Button
        text="Edit"
        onClick={(e, { store }) => {
          edit(store.get(m.$record))
        }}
      />
    )
  }
]}

Use value for computed display values while keeping field for sorting:

{
  header: "Status",
  field: "active",
  value: { expr: "{$record.active} ? 'Yes' : 'No'" }
}

Headers

The header property can be a simple string or a configuration object for advanced scenarios like multi-row headers, custom tools, or spanning columns:

columns={[
  {
    header: {
      text: "Name",
      colSpan: 2,
      align: "center"
    },
    field: "fullName"
  },
  {
    header: {
      text: "Sales",
      tool: <Icon name="drop-down" />,
      allowSorting: false
    },
    field: "sales"
  }
]}

Use colSpan and rowSpan to create complex multi-row headers. The tool property allows adding custom components like filter dropdowns or menus inside the header.

Dynamic Columns

Use columnParams and onGetColumns to dynamically generate columns based on data or user preferences:

<Grid
  records={m.records}
  columnParams={m.visibleColumns}
  onGetColumns={(params) => {
    const baseColumns = [{ header: "Name", field: "name" }];
    const dynamicColumns = params.map((col) => ({
      header: col.label,
      field: col.field,
    }));
    return [...baseColumns, ...dynamicColumns];
  }}
/>

Whenever columnParams changes, onGetColumns is called to recalculate the column configuration. This is useful for user-configurable column visibility, pivot tables, or data-driven column generation.

See also: Complex Headers, Column Resizing, Column Reordering, Fixed Columns, Dynamic Columns

Grouping

Grids support multi-level grouping with aggregates. Define grouping levels using the grouping property:

<Grid
  records={m.records}
  grouping={[
    {
      key: { continent: m.$record.continent },
      showFooter: true,
    },
  ]}
  columns={[
    { header: "Continent", field: "continent" },
    { header: "Name", field: "fullName" },
    {
      header: "Sales",
      field: "sales",
      aggregate: "sum",
      footer: { tpl: "{$group.sales:n;2}" },
    },
  ]}
/>

Each grouping level supports the following options:

PropertyTypeDescription
keyobjectObject with name/selector pairs defining how records are grouped. Values are available as $group.keyName.
showFooterbooleanShow a footer row with aggregate values after each group.
showHeaderbooleanShow a header row within each group. Useful for long printable reports.
showCaptionbooleanShow a caption row at the start of each group. Caption content is defined in the column’s caption property.
textstringA selector for text available as $group.$name in templates.
comparerfunctionA function to determine group ordering.

Column aggregates (sum, count, avg, distinct) are automatically calculated and available in footer/caption templates via $group.

For dynamic grouping, use groupingParams and onGetGrouping:

<Grid
  records={m.records}
  groupingParams={m.selectedGrouping}
  onGetGrouping={(params) => {
    if (!params) return null;
    return [
      {
        key: { value: m.$record[params.field] },
        showFooter: true,
      },
    ];
  }}
  columns={columns}
/>

Whenever groupingParams changes, onGetGrouping is called to recalculate the grouping configuration. This allows users to change grouping at runtime.

See also: Grouping, Dynamic Grouping

Drag & Drop

Grids support drag and drop for reordering rows, moving data between grids, and column reordering. Configure dragSource and dropZone to enable this functionality:

<Grid
  records={m.records}
  dragSource={{ mode: "move", data: { type: "record" } }}
  dropZone={{ mode: "insertion" }}
  onDrop={(e, { store }) => {
    // Handle the drop - reorder records
    store.update(m.records, (records) => {
      // Move record from e.source.recordIndex to e.target.insertionIndex
    });
  }}
  columns={columns}
/>

The dropZone.mode can be insertion (shows insertion line between rows) or preview (highlights the target row). Use onDropTest to control which drops are allowed.

See also: Row Drag and Drop

Examples

Grid Configuration

Data

PropertyTypeDescription
recordsarrayAn array of records to be displayed in the grid.
keyFieldstringField used as unique record identifier. Improves performance on sort by tracking row movement.
columnsarrayAn array of column configurations. See Column Configuration below.
columnParamsanyParameters passed to onGetColumns for dynamic column generation.
onGetColumnsfunctionCallback to dynamically generate columns when columnParams changes.
recordNamestringRecord binding alias. Default is $record.
recordAliasstringAlias for recordName.
dataAdapterobjectData adapter configuration for grouping and tree operations.
emptyTextstringText displayed when grid has no records.

Selection

PropertyTypeDescription
selectionobjectSelection configuration. See Selections for details.
scrollSelectionIntoViewbooleanScroll selected row into view. Default is false.
onCreateIsRecordSelectablefunctionCallback to create a function that checks if a record is selectable.

Sorting

PropertyTypeDescription
sortFieldstringBinding to store the name of the field used for sorting.
sortDirectionstringBinding to store the sort direction (ASC or DESC).
sortersarrayBinding to store multiple sorters for server-side sorting.
preSortersarraySorters prepended to the actual list of sorters.
defaultSortFieldstringDefault sort field when no sorting is set.
defaultSortDirectionstringDefault sort direction (ASC or DESC).
remoteSortbooleanSet to true if sorting is done server-side.
clearableSortbooleanAllow clearing sort by clicking header a third time.
sortOptionsobjectCollator options for sorting. See MDN Intl.Collator for available opts.

Grouping

PropertyTypeDescription
groupingarrayAn array of grouping level definitions.
groupingParamsanyParameters passed to onGetGrouping for dynamic grouping.
onGetGroupingfunctionCallback to dynamically generate grouping when params change.
preserveGroupOrderbooleanKeep groups in the same order as source records.

Filtering

PropertyTypeDescription
filterParamsanyParameters passed to onCreateFilter callback.
onCreateFilterfunctionCallback to create a filter predicate from filterParams.

Appearance

PropertyTypeDescription
scrollablebooleanSet to true to add a vertical scroll and fixed header. Grid should have height or max-height set.
borderbooleanSet to true to add default border. Automatically set if scrollable.
vlinesbooleanSet to true to add vertical gridlines.
headerModestringHeader appearance: plain or default.
showHeaderbooleanShow grid header within groups. Useful for long printable grids. Default is false.
showFooterbooleanShow grid footer. Default is false.
fixedFooterbooleanSet to true to add a fixed footer at the bottom of the grid.
rowClassstringAdditional CSS class to be added to each grid row.
rowStylestring | objectAdditional CSS styles to be added to each grid row.

Performance

PropertyTypeDescription
cachedbooleanSet to true to enable row caching for better performance.
bufferedbooleanSet to true to render only visible rows. Requires scrollable.
bufferSizenumberNumber of rendered rows in buffered grids. Default is 60.
bufferStepnumberNumber of rows to scroll before buffer recalculation.
measureRowHeightsbooleanCache variable row heights in buffered grids. Default is false.
lockColumnWidthsbooleanLock column widths after first render. Useful for pagination.
preciseMeasurementsbooleanEnable sub-pixel measurements. Useful for grids with many columns or small zoom.

Infinite Scrolling

PropertyTypeDescription
infinitebooleanEnable infinite scrolling.
onFetchRecordsfunctionCallback to fetch records during infinite loading.

Cell Editing

PropertyTypeDescription
cellEditablebooleanSet to true to enable cell editing. Columns must specify editor field.
onBeforeCellEditfunctionCallback before cell edit. Return false to prevent edit mode.
onCellEditedfunctionCallback after a cell has been successfully edited.

Focus & Hover

PropertyTypeDescription
focusablebooleanSet to true or false to explicitly control if grid can receive focus.
hoverChannelstringIdentifier for hover effect synchronization across components.
rowHoverIdstring | numberUnique record identifier within the hover sync group.

Row Callbacks

PropertyTypeDescription
onRowClickfunctionCallback executed when a row is clicked.
onRowDoubleClickfunctionCallback executed when a row is double-clicked.
onRowContextMenufunctionCallback executed when a row is right-clicked.
onRowKeyDownfunctionCallback executed on key down in a focused row.

Column Callbacks

PropertyTypeDescription
onColumnContextMenufunctionCallback executed when a column header is right-clicked.
onColumnResizefunctionCallback executed after a column has been resized.

Other

PropertyTypeDescription
scrollResetParamsanyParameters whose change will reset scroll position.
onTrackMappedRecordsfunctionCallback to track and retrieve displayed (filtered) records.
onReffunctionCallback to get grid component and instance references on init.

Column Configuration

PropertyTypeDescription
fieldstringName of the property inside the record to display.
headerstring | objectText or configuration object for the column header.
formatstringFormat string for cell values.
alignstringColumn alignment: left, right, or center.
sortablebooleanSet to true to make the column sortable.
sortFieldstringAlternative field used for sorting.
primarySortDirectionstringInitial sort direction on first click: ASC or DESC.
aggregatestringAggregate function: sum, count, distinct, avg.
aggregateFieldstringField used for aggregation if different from field.
footerstringValue to render in the footer.
editablebooleanIndicate if cell is editable. Default is true.
editorobjectCell editor configuration.
draggablebooleanMake column draggable for reordering.
resizablebooleanMake column resizable.
mergeCellsstringMerge adjacent cells: same-value or always.

Column Header Configuration

When header is an object, the following properties are available:

PropertyTypeDescription
textstringHeader text.
alignstringHeader text alignment: left, right, or center.
allowSortingbooleanEnable or disable sorting on the column. Default is true.
colSpannumberNumber of columns the header cell should span. Default is 1.
rowSpannumberNumber of rows the header cell should span. Default is 1.
toolobjectA component rendered inside the header for custom menus or filters.
resizablebooleanSet to true to make the column resizable.
widthnumberBinding to store column width after resize.
tooltipstring | objectTooltip configuration for the header.

Drag & Drop Configuration

PropertyTypeDescription
dragSourceobjectDrag source configuration. Define mode as move or copy and additional data.
dropZoneobjectDrop zone configuration. Define mode as insertion or preview.
allowsFileDropsbooleanAllow grid to receive drag and drop operations containing files.

Drag & Drop Callbacks

onDragStart(e: DragEvent, instance: Instance) - Called when the user starts dragging a row.

  • e - The native drag event.
  • instance - The grid instance.

onDragEnd(e: DragEvent, instance: Instance) - Called when the user stops dragging.

  • e - The native drag event.
  • instance - The grid instance.

onDragOver(e: GridDragEvent, instance: Instance): boolean? - Called when the user drags over another item. Return false to prevent dropping.

  • e - Grid drag event containing source and target with record indices.
  • instance - The grid instance.

onDrop(e: GridDragEvent, instance: Instance) - Called when a drop occurs. Use it to update data such as rearranging the list.

  • e - Grid drag event containing source and target with record indices and insertion index.
  • instance - The grid instance.

onDropTest(e: DragEvent, instance: Instance): boolean - Checks whether a drop action is allowed. Return false to reject.

  • e - The native drag event.
  • instance - The grid instance.

onRowDragOver(e: GridRowDragEvent, instance: Instance): boolean? - Called when dragging over a specific row. Useful for tree grids.

  • e - Grid row drag event containing source record and target row info.
  • instance - The grid instance.

onRowDrop(e: GridRowDragEvent, instance: Instance): boolean? - Called when dropping onto a row. Use it to attach a node to a subtree.

  • e - Grid row drag event containing source record and target row info.
  • instance - The grid instance.

onRowDropTest(e: DragEvent, instance: Instance): boolean - Checks whether a row drop action is allowed.

  • e - The native drag event.
  • instance - The grid instance.

onColumnDrop(e: GridColumnDropEvent, instance: Instance): boolean? - Called when a column is dropped. Use it for column reordering.

  • e - Column drop event containing column info.
  • instance - The grid instance.

onColumnDropTest(e: DragEvent, instance: Instance): boolean - Checks whether a column drop is valid.

  • e - The native drag event.
  • instance - The grid instance.

onCreateIsRecordDraggable(): (record) => boolean - Returns a predicate function that determines which records can be dragged.