Table of Contents

Datagrid

Live demos in the Datagrid menu entry.

Renders a datagrid of the current data source.

The visible columns are the properties of the UI view whose visible property is true.

If the datagrid is editable or the datagrid is in a unbound UI view, grouping is not allowed.

Node name : datagrid

Attributes

Attribute Type Required Default value Description
editable bool false false A value indicating whether the datagrid is editable.
groupable bool false true A value indicating whether the datagrid is groupable.
indicator-column bool false true A value indicating whether the indicator column is displayed.
selection-column bool false true A value indicating whether the selection column is displayed.
group-panel-visible bool false false A value indicating whether the group panel is visible.
no-data-overlay bool false true A value indicating whether an overlay should be displayed when there is no data.
row-height int false 40 The row height.
auto-row-height bool false false A value indicating whether the rows have automatic height.
add-row bool false true A value indicating whether the add row is displayed (when the datagrid is editable).
boolean-display-mode string (checkbox, switch) false checkbox The type of component used to render a boolean property.
resize-columns-on-refresh bool false false A value indicating whether the columns should be resized on refresh. If false, columns are automatically resized when the data is first loaded. If true, resizing occurs on every refresh (e.g., data reloading, after editing a cell, etc.). This may affect rendering performance and slow down the UI.
infinite-scrolling bool false false (overrideable in cluster configuration) A value indicating whether the infinite scrolling is enabled.
exportable bool false true A value indicating whether the datagrid is exportable.
column-picker bool false true A value indicating whether the column picker is enabled.
source GroupeIsa.Neos.Application.UI.IUIView[] false The ViewModel data source. The source to which the datagrid is bound. This attribute is specifically designed for sub-datagrids (nested collections from a parent data source).
row-detail-visibility-mode string (single, multiple) false single A value indicating the visibility mode of the row detail (if several row details can be displayed simultaneously).
row-detail-expanded-by-default bool false false A value indicating whether the row details are expanded by default. When true, all row details are automatically expanded when data is loaded and when new rows are added.
row-click-selection-mode string (replace, toggle) false replace A value indicating how a click on a row changes the selection.
- replace: the clicked row is selected and the other rows are unselected.
- toggle: the selection of the clicked row is toggled and the other rows keep their selection. See the row selection section.
summary-tag bool false false A value indicating whether the tag of summary is displayed.
row-dragover string false Name of the method called when a row is dragged over another row. See the row drag and drop section.
row-drop string false Name of the method called when a row is dropped. See the row drag and drop section.
row-draggable bool false false A value indicating whether the rows can be dragged out of the datagrid. See the drag rows out of the datagrid section.
external-row-dragover string false Name of the method called when data that does not come from the datagrid is dragged over it. See the drop on the datagrid section.
external-row-drop string false Name of the method called when data that does not come from the datagrid is dropped on it. See the drop on the datagrid section.
colspan string false Name of the method called to merge cells of a row. The method takes as its parameter an object of type IDatagridColspanEventArgs<T> (where T is the type of item bound to the row) and must return an int value indicating the colspan of the cell.
footer-counts bool false A value indicating whether the footer counts are visible.
card-mode bool false A value indicating whether the datagrid is displayed in card mode.
card-mode-scope string (window, container) false window Scope used to determine when the datagrid switches between card mode and grid mode.
- window: the breakpoint is based on the browser window width.
- container: the breakpoint is based on the width of the datagrid's container element.
This attribute is ignored if card-mode is explicitly set.
card-mode-breakpoint number or string (extrasmall, small, medium, large, extralarge) false medium (768) Width threshold at which the datagrid switches between card mode and grid mode. This attribute is ignored if card-mode is explicitly set.
card-mode-header-property-name string false Name of the property used as the header title in card mode.
input-number-type string (default, calculable) false default A value indicating the edit component to columns with numberic data type
row-actions-location string (overlay, column) false Theme (overlay in the standard themes) Location of the row actions: overlay displays them over the end of the hovered row, column in a column frozen at the right end of the datagrid. When not set, the RowActionsLocation attribute of the Datagrid component of the theme applies.

Example

<datagrid editable="true" groupable="true" selection-column="true" group-panel-visible="true" />

Infinite scrolling

<datagrid infinite-scrolling="true" layout:height="fill" />

The default value of the infinite-scrolling attribute can be set in the YAML cluster configuration file:

UIDefaultBehavior:
  DatagridInfiniteScrolling: true
Important

For infinite scrolling to work, the datagrid must have a scrollbar. This requires the datagrid to have a constrained height, which can be achieved in two ways:

  • Using a fixed value: Set an explicit height in pixels (e.g., layout:height="500").
  • Using the fill value: Set layout:height="fill" to occupy the full available height of the parent container. In this case, you typically need to apply layout:height="fill" to all parent elements of the datagrid so that the height is correctly propagated and each container adjusts to its parent's height.
Note

When the UI view opens in popup (auto size) mode, the popup has no fixed height and adapts to its content, which prevents infinite scrolling from working. Two solutions are available:

  • Open the UI view in popup (full size) mode instead.
  • Set a fixed height on the root container of the UI view (e.g., layout:height="800" on the neos-template-list element).

Cell display mode

Cells have two display modes.

  • The default mode when the focus is not on a cell (or when the grid is not editable). The default content is the formatted value. You can override it using the <column-template> node.
  • The edit mode when the focus is on a cell (and the grid is editable). The default content is the automatically determined editing component. You can override it using the <column-edit-template> node.

Cell style

It is possible to conditionally style cells using UI view style rules.

The datagrid supports automatic navigation based on several properties defined on the header of the UI view :

  • Adding UI view : creating a new element in the UI view will navigate to the view defined in this option.
  • Editing UI view :
    • Without having defined the property used as edit link: clicking on the pencil icon will navigate to the view defined in this option to edit the line.
    • With having defined the property used as edit link: clicking on the property edit link will navigate to the view defined in this option to edit the line.

Columns

Width

By default, the width of the columns is determined by the content of the cells. You can use the Width attribute of the Grid section to set :

  • a fixed width (in pixels).
  • or a dynamic width in the x* format where column widths are proportional to the number before the star. For example, if a datagrid has three columns with widths 100, *, and 3*:
    • the first column is 100 pixels wide
    • the second column takes up 1/4th of the remaining space
    • the last column takes up the remaining 3/4ths of the remaining space

You can also define a minimum and maximum width using the Minimum width and Maximum width attributes. The minimum can be interesting in case of datagrid with a lot of columns.

Grouping and summaries

Grouping

Grouping is available when the groupable attribute is set to true (default value). The user can drag and drop columns to the group panel to group the data by the selected columns if the panel group is visible or right click on the column. The group panel is visible when the group-panel-visible attribute is set to true (default value = false). It is possible to define a group summary type for each column using the Group summary type attribute available in the Grid section. The possible values are available in this documentation. Note that group summary types differ depending on the type of data in the column.

Client-side grouping

By default, grouping is handled on the server side. On the UI view loading, a request is sent to retrieve the groupings. If the user expands a group, an additional request is made to fetch the items within that group.

Client-side grouping is also supported. To enable it, set the GroupingBehavior.ExecutionSide property to GroupingExecutionSide.Client in the Initialized event rule. Note that the data source must not be paginated; the entire dataset must be loaded at once.

For large data sources, server-side grouping is recommended to ensure optimal performance and minimize client-side resource usage. In contrast, client-side grouping is best suited for smaller datasets, as it eliminates the need for additional server requests and provides a more responsive user experience.

With client-side grouping, you can automatically expand groupings on load by setting the GroupingBehavior.ExpandGroupsOnLoad property to true. This functionality is not available with server-side grouping.

Summaries

Summaries are available for each column using the Total summary type attribute available in the Grid section. The possible values are available in this documentation. Note that total summary types differ depending on the type of data in the column.

By default, a tag indicating the type of summary is displayed before the value.

This tag can be hidden by setting the summary-tag attribute to false on the datagrid.

It is also possible to modify the tag of a specific summary globally by code (in a Initialized global event rule) :

SummaryTypes.Sum.Tag = "∑"; // or null to hide the tag

It is also possible to modify the tag of a specific summary of a specific UI view property by code (in a Initialized UI view event rule by code) :

Properties.Total.SummaryTypes.Sum.Tag = "∑"; // or null to hide the tag

The content of the datagrid footer can be customized using the footer-template node.

<datagrid>
  <footer-template>
    <!-- Content -->
  </footer-template>
</datagrid>

Card mode

On a small smartphone screen, the datagrid is displayed in card mode, where each row is rendered as an individual card instead of a table row. The features in card mode are limited.

Card template

The cards contain default content. However, this is rarely what you actually want, which is why you can specify your own content using the card-template node.

<datagrid>
  <card-template>
    <horizontal-layout vertical-align="center">
      <label property-name="Name" item="@Item" />
      <text property-name="Name" item="@Item" />
    </horizontal-layout>
  </card-template>
</datagrid>

Binding to computed sources

The source attribute on a datagrid is specifically designed for sub-datagrids (nested collections within the current data source).

When you need to bind a datagrid to a computed property that filters or transforms a collection, you must wrap the datagrid in a <context> element instead of binding directly to the datagrid's source attribute.

Correct approach for computed sources:

<context source="@Computeds.FilteredOrderDetails">
  <datagrid editable="true" />
</context>

For more details on using computed sources, see the <context> component documentation. To see an example of a sub-datagrid with the source attribute, refer to the nested datagrid example in row detail templates.

Row actions

The actions located on the datagrid rows (DatagridRow location) are displayed on the hovered row:

  • overlay: the actions are displayed over the end of the row, on a background that hides the cells they cover. This is the default behavior of the standard themes.
  • column: the actions are displayed in a column frozen at the right end of the datagrid, so they never hide any data. They are visible on the hovered row, and on touch screens, which cannot hover, on the current row. When columns are scrolled horizontally under it, they fade out into the actions column.

Repeated on every row, the actions are displayed without border: an action with the Default style is displayed as Ghost, and an action with the Danger style as GhostDangerSubtle, with the color of the other actions until it is hovered, when it turns red. An action with another style keeps it.

With the keyboard, the Tab key goes from the last cell of a row to the actions of that row, then from one action to the next, and finally to the first cell of the next row. Shift+Tab goes the other way. In the overlay location, the actions are displayed on the row while the focus is in them. Enter and Space run the focused action.

The column location cannot be combined with data columns frozen on the left (DatagridFrozen property): the datagrid then falls back to overlay.

The location is set by the row-actions-location attribute of the datagrid. When it is not set, the RowActionsLocation attribute of the Datagrid component of the theme applies, so that a theme can choose the location for all the datagrids of the application.

<datagrid row-actions-location="column" />

Row selection

The user selects rows with the mouse, the keyboard or the selection column. The clicked or reached row always becomes the current row, even when the action unselects it.

By default (row-click-selection-mode="replace"), a click on a row replaces the whole selection. When the user mostly needs to select several rows, for example in a selection UI view, set the row-click-selection-mode attribute to toggle, so that a click only changes the selection of the clicked row:

<datagrid row-click-selection-mode="toggle" />

The following table describes the effect of each action on the selection in both modes:

Action replace (default) toggle
Click Selects the row and unselects the other rows. Toggles the selection of the row, without changing the other rows.
Ctrl + click Toggles the selection of the row, without changing the other rows. Same as replace.
Shift + click Selects the rows between the last clicked or reached row and the clicked row, without changing the other rows. If the clicked row was already selected, the rows in between are unselected instead. Same as replace.
Right click On a row that is not selected: selects the row and unselects the other rows. On a selected row: leaves the selection unchanged, so that the context menu applies to all the selected rows. On a row that is not selected: adds the row to the selection. On a selected row: leaves the selection unchanged.
Checkbox of the selection column Toggles the selection of the row, without changing the other rows. Same as replace.
Checkbox of the selection column header Selects or unselects all the loaded rows. With pagination, when not all the data is loaded, the user first confirms that only the displayed rows are selected. With infinite scrolling, the checkbox stays disabled until all the data is loaded. Same as replace.
Arrow keys, Enter, Tab Selects the reached row and unselects the other rows. Same as replace: moving with the keyboard replaces the selection made with clicks.
Shift + arrow up/down Selects the rows between the last clicked or reached row and the reached row, like a Shift + click. Same as replace.
Note
  • Without the selection column (selection-column="false"), only one row can be selected: Ctrl + click, Shift + click and Shift + arrow up/down select only the clicked or reached row, and the toggle mode is forced back to replace.
  • The toggle mode is meant for read-only datagrids. On an editable datagrid, a click on a cell to edit it also toggles the selection of its row.
  • In card mode, the row-click-selection-mode attribute has no effect: a press on a card selects only that card, and a long press toggles its selection without changing the other cards.

Row detail

It is possible to add a detail to each row. You can enable it using the <row-detail-template> node.

Row drag and drop

It is possible to enable row drag & drop by setting the row-drop attribute.

The method you assign to the row-drop attribute is executed when a dragged row is dropped. The method takes as parameter an object of type IDatagridDragEventArgs<T> (where T is the type of item bound to the row) and returns void. The method must be synchronous.

If you want to condition the drop, you need to specify a method to the row-dragover attribute. The method takes as its parameter an object of type IDatagridDragEventArgs<T> (where T is the type of item bound to the row) and must return a boolean indicating whether the dragged row can be dropped. The method must be synchronous.

In the arguments of type IDatagridDragEventArgs<T>, you'll find the following properties:

  • Item (T) : The dragged item.
  • NewIndex (int) : The index where the dragged item is being dropped.

Reordering moves a single row: when several selected rows are dragged, they cannot be dropped in their own datagrid.

Drag rows out of the datagrid

Setting the row-draggable attribute to true displays the drag handle column and lets the user drag rows out of the datagrid, to another datagrid or to any node bearing the drag and drop directives. The attribute can be combined with row-drop.

When the dragged row is selected, all the selected rows are dragged, in display order. Otherwise, only the dragged row is. When several rows are dragged, a badge showing their count follows the pointer. The handle only drags: pressing it does not change the selection nor the current row.

The drop target reads the dragged rows with the GetDatagridDragData() method of its arguments, which returns an IDatagridDragData object, or null when the drag does not come from a datagrid:

  • UIViewName (string) : The name of the UI view of the dragged items. Compare it to the name of the expected UI view to accept only its rows.
  • Items (object[]) : The dragged items, in display order.

Example of a dragdrop:drop method that receives products:

IDatagridDragData? data = args.GetDatagridDragData();
if (data?.UIViewName == nameof(ProductUI))
{
    foreach (object item in data.Items)
    {
        await Methods.AddToCartAsync((ProductUI)item);
    }
}

Drop on the datagrid

A datagrid accepts data dragged from elsewhere (another datagrid, a draggable node, files...) by setting the external-row-drop attribute. The rows dragged from the datagrid itself are handled by row-drop, not by external-row-drop.

The method you assign to the external-row-drop attribute is executed when the data is dropped. The method takes as parameter an object of type IDatagridExternalDropEventArgs and returns void.

If you want to condition the drop, you need to specify a method to the external-row-dragover attribute. The method takes as its parameter an object of type IDatagridExternalDragEventArgs and must return a boolean indicating whether the data can be dropped. The method must be synchronous.

Both arguments provide the methods of the drag and drop directive arguments (GetDatagridDragData(), GetInternalObjectData(), GetStringData(), HasFiles(), and GetFiles() on drop), as well as:

  • NewIndex (int) : The index in the data source (Datasource) where the data is dropped: the index of the item of the row under the pointer when the pointer is on its upper half, the next index when it is on its lower half, and the number of items of the data source outside the rows. Like for row-drop, it is an index in the data source and not in the displayed rows, which differ when the rows are filtered or sorted.

Example:

<datagrid row-draggable="true" />
<datagrid source="@Fields.Cart" external-row-dragover="CanDropProducts" external-row-drop="DropProducts" />
  • CanDropProducts method:
    • args: IDatagridExternalDragEventArgs
return args.GetDatagridDragData()?.UIViewName == nameof(ProductUI);
  • DropProducts method:
    • args: IDatagridExternalDropEventArgs
IDatagridDragData data = args.GetDatagridDragData()!;
int index = args.NewIndex;
foreach (object item in data.Items)
{
    Methods.InsertInCart((ProductUI)item, index++);
}

The rows dragged from a datagrid can only be dropped in the current browser tab.

Reactivity in datagrid

In most cases, a property with getter will be automatically reactive in the datagrid.

However, there are cases where it's not. For example, when the getter code does not reference a scalar property of the element: return Item.OrderDetails.Count. This is because the datagrid does not know the OrderDetailsCount property and cannot monitor it automatically. You therefore need to make the property reactive by calling the EnableWatcher() method as soon as the expression uses elements (property, field or computed) unknown to the datagrid.

To make the property reactive, call the EnableWatcher() method on the UI view property in the Initialized UI view event rule: Properties.OrderDetailsCount.EnableWatcher().

If the getter code references a property of an element in a list (Item.OrderDetails.Count(d => d.UnitPrice > 100)), enable a deep watcher: Properties.OrderDetailsCount.EnableWatcher(true).

Important

Deep watch requires traversing all nested properties in the watched object, and can be expensive when used on large data structures. Use it only when necessary and beware of the performance implications.

See also

The standard list layout using the datagrid is available here.