Skip to main content

Datagrid Component

DataGrid is a component that displays data in a grid format. It supports pagination, sorting, and filtering. The component can be used to display data from a GraphQL query.

View Types

The DataGrid supports three view types: table (default), collection, and list.

View TypeDescription
tableTraditional table grid with rows and columns (default)
collectionResponsive grid of cards, ideal for visual browsing
listCompact single-column list using MUI List components

Table View (Default)

The standard table view displays data in rows and columns:

views:
- name: tableView
displayName:
en-US: Table View
viewType: table # or omit - table is default
columns:
- name: name
- name: email
- name: status

Collection View

Collection view displays data as a responsive grid of cards:

views:
- name: cardView
displayName:
en-US: Card View
viewType: collection
columns:
- name: name
- name: email
- name: status
collection:
itemSize:
xs: 12 # 1 card per row on mobile
sm: 6 # 2 cards per row on small screens
md: 4 # 3 cards per row on medium screens
lg: 3 # 4 cards per row on large screens
spacing: 3
dividers: false
children: # Optional custom template
- component: card
props:
elevation: 2
children:
- component: cardContent
children:
- component: text
props:
variant: h6
value: "{{item.name}}"
- component: text
props:
variant: body2
color: textSecondary
value: "{{item.email}}"

Collection Properties

PropertyTypeDefaultDescription
childrenarrayauto-generatedCustom YAML template for each item
itemNamestring'item'Variable name for current item
itemSizenumber | object{ xs: 12, sm: 6, md: 4, lg: 3 }Grid column size
spacingnumber3Gap between items
emptyMessagestring'No items to display'Empty state message

List View

List view displays data in a compact, single-column format:

views:
- name: listView
displayName:
en-US: List View
viewType: list
columns:
- name: name
- name: email
- name: department
- name: status
list:
dense: true
dividers: true
primaryField: name
secondaryField: email
avatarField: avatarUrl

List Properties

PropertyTypeDefaultDescription
childrenarrayauto-generatedCustom YAML template for each item
itemNamestring'item'Variable name for current item
dividersbooleanfalseShow dividers between items
densebooleanfalseUse compact spacing
disablePaddingbooleanfalseRemove list padding
emptyMessagestring'No items to display'Empty state message
primaryFieldstring-Field for primary text
secondaryFieldstring-Field for secondary text
avatarFieldstring-Field for avatar URL

List View with Custom Template

views:
- name: customList
viewType: list
columns:
- name: title
- name: description
list:
dividers: true
children:
- component: listItemText
props:
primary: "{{item.title}}"
secondary: "{{item.description}}"
primaryTypographyProps:
fontWeight: bold

Multiple View Types

Allow users to switch between different view types:

component: dataGrid
name: productsGrid
props:
options:
query: products
entityKeys:
- productId
enableViews: true
views:
- name: table
displayName:
en-US: Table
viewType: table
columns:
- name: name
- name: sku
- name: price
- name: stock

- name: cards
displayName:
en-US: Cards
viewType: collection
columns:
- name: name
- name: sku
- name: price
collection:
itemSize:
xs: 12
sm: 6
md: 4

- name: list
displayName:
en-US: List
viewType: list
columns:
- name: name
- name: sku
- name: price
list:
dense: true
dividers: true
primaryField: name
secondaryField: sku

Example

component: dataGrid
name:
inputs:
props:
refreshHandler: "countries"
enableStore: true # enable store for the datagrid, Row data will be placed in the store
views:
- name: allCountries
viewType: "grid" # collection, grid, Default is grid
itemComponent: # render item for collection
component: card
props:
title: "{{ item.name }}"
description: "{{ item.countryCode }}"
image: "{{ item.image }}"
actions:
- component: button
props:
label: "View" # action to execute when the button is clicked
onClick:
- navigate: "countries/{{ item.countryCode }}"
displayName:
en-US: All Countries
enableEdit: true
enableSelect: "Multiple"
onRowClick: # action to execute when a row is clicked (override default action)"
columns:
- name: countryCode
label:
en-US: Country code
- name: name
label:
en-US: Name
editor:
type: text
showAs:
component: text
props:
value: "{{ name }}"
- name: created
label:
en-US: Created
- name: createdByUser.userName
label:
en-US: Created by
- name: lastModified
label:
en-US: Last modified
- name: lastModifiedByUser.userName
label:
en-US: Last modified by
- name: customField
value: "{{ item.customField }}"
filter:
orderBy: # default sorting for the datagrid
- name: countryCode
direction: ASC
childViews: # child views for the datagrid
- name: states # field name / resolver for GraphQL query
onRowClick: # action to execute when a row is clicked
columns:
- name: stateCode
label:
en-US: State code
options:
query: countries
rootEntityName: Country
enableToolbar: true # show toolbar in the datagrid, default is true
enableColumns: true # enable column selection in the datagrid, default is true
enableFilter: true # enable filtering in the datagrid, default is true
enableSearch: true # enable search in the datagrid, default is true
entityKeys:
- countryCode
enableDynamicGrid: true
navigationType: browser # browser or store,
editableOptions:
onNewRow: # mutation to create a new record
mutation:
onRowChange: # mutation to update a record
mutation:
onRowDelete: # mutation to delete a record
mutation:
itemTemplate: ?
countryCode: "{{ data.countryCode }}"
onDataLoad:
- name: "setCountryCode"
args:
countryCode: "{{ data[0].countryCode }}"
onEditClick:
navigate: countries/{{ countryCode }}
onRowClick:
dialog:
name: updateCountryDialog
props:
permission: System/Countries/Update
title:
en-US: "Update Country"
countryCode: "{{ countryCode }}"
organizationId: "{{ organizationId }}"
component:
layout:
component: layout
props:
children:
- component: Countries/UpdateCountry
defaultView: allCountries
toolbar:
- component: dropdown
props:
label:
en-US: Actions
name: actionscountries
icon: activity
options:
variant: secondary
items:
- label:
en-US: Import Countries
onClick: []
- label:
en-US: Export Countries
onClick: []
children:

Change Tracking & Row Highlights

The DataGrid supports automatic change tracking that detects new and updated rows across refreshes, highlighting them visually. Highlights accumulate across multiple refresh cycles, with each highlighted row having its own per-row TTL (Time-To-Live) measured in refresh cycles.

Enabling Change Tracking

Set enableChangeTracking: true in the DataGrid options along with a refreshHandler and refreshInterval:

component: dataGrid
name: pickupOrdersGrid
props:
refreshHandler: pickupOrders
options:
query: pickupOrders
entityKeys:
- orderId
enableChangeTracking: true
enableRefresh: true
refreshInterval: 30000
highlightNew: true
highlightUpdated: true
highlightForRefreshes: 5

Change Tracking Options

PropertyTypeDefaultDescription
enableChangeTrackingbooleantrueEnable/disable change tracking
highlightNewbooleantrueHighlight newly added rows
highlightUpdatedbooleantrueHighlight rows with updated values
highlightForRefreshesnumber1Per-row TTL — number of refresh cycles a highlight persists

How It Works

  1. Snapshot: On each data fetch, the DataGrid takes a snapshot of the current data.
  2. Comparison: On the next refresh (auto-refresh or external), the new data is compared against the snapshot using entityKeys to match rows.
  3. Highlight accumulation: New and updated rows are added to a highlight map with a fresh TTL. Existing highlights have their TTL decremented by 1 each cycle. When a row's TTL reaches 0, its highlight is removed.
  4. Per-row independence: Each row's TTL is independent — older highlights expire first while newer ones persist.

Per-Row TTL Example

With highlightForRefreshes: 3:

Refresh #0 → Initial load, 20 rows, snapshot taken
Refresh #1 → 5 new rows arrived → A(3) B(3) C(3) D(3) E(3)
Refresh #2 → 1 new row arrived → A(2) B(2) C(2) D(2) E(2) F(3)
Refresh #3 → nothing new → A(1) B(1) C(1) D(1) E(1) F(2)
Refresh #4 → 2 new rows arrived → F(1) G(3) H(3) (A–E expired)
Refresh #5 → nothing new → G(2) H(2) (F expired)

External Refresh with Highlight Options

The refresh action now supports an optional options object to control highlighting behavior per-call. These options override the grid-level defaults for that specific refresh:

- refresh: "pickupOrders"
options:
highlightNew: true
highlightForRefreshes: 1

See Actions — refresh for details.

Refresh Options Resolution Order

Options are resolved with highest priority first:

  1. Refresh action options — per-call override (external refresh only)
  2. DataGrid options — grid-level defaults (auto-refresh always uses these)
  3. Global defaultshighlightNew: true, highlightUpdated: true, highlightForRefreshes: 1

Behavior Details

ScenarioBehavior
Auto-refresh (polling timer)Grid-level defaults apply; highlights accumulate
External refresh action (no options)Grid-level defaults apply
External refresh action (with options)Action options override grid defaults
Row re-highlighted before TTL expiresTTL resets to fresh value
Pagination changeComparison skipped; TTLs are not decremented
Filter/search/view changeAll highlights cleared; snapshot reset
Cross-window refreshOptions propagate via postMessage; each window accumulates independently

Disabling Highlights on a Specific Refresh

- refresh: "pickupOrders"
options:
highlightNew: false
highlightUpdated: false

Filter Persistence

By default, the DataGrid persists filter state (both filter column selections and filter values) across route navigation within the same browser session. This means that when a user applies filters on a grid, navigates away to another page, and then returns, their filters are automatically restored.

How It Works

Filter state is managed by a singleton Zustand store (gridFilterStore) that lives outside the component tree. Unlike per-page state (which resets on navigation), this store survives route changes because it is not tied to any UiContextProvider.

  • Filter columns (which filter inputs are visible) are persisted when the user adds or removes filter columns, and when view defaults are first applied.
  • Filter values (the actual selected/entered filter criteria) are persisted every time the user changes a filter.
  • On mount, the DataGrid reads any previously persisted state for its gridName and initializes with those values instead of empty defaults.

Behavior Details

ScenarioBehavior
User sets filters, navigates away, returnsFilters are restored automatically
User opens grid for the first timeView default filters apply as normal
View has default filter columns, user hasn't customizedDefaults are persisted on first load so they're available on return
User adds/removes filter columnsChanges are persisted immediately
Page refresh (full reload)Filters reset (store is in-memory only)
info

Filter persistence is in-memory only — it does not survive a full page refresh or new browser tab. It is designed specifically for SPA route navigation within a single session.

DataGrid Options

The options object is used to configure the datagrid. The options object has the following properties:

  • query - The name of the GraphQL query to use to fetch data for the datagrid.
  • rootEntityName - The name of the root entity in the GraphQL query.
  • entityKeys - An array of entity keys to use to identify the entity in the datagrid.
  • enableDynamicGrid - A boolean value that indicates whether the datagrid is dynamic.
  • navigationType - The type of navigation to use when navigating to a new page.
  • editableOptions - An object that contains the editable options for the datagrid.
  • onDataLoad - An array of actions to execute when the data is loaded.
  • onEditClick - An action to execute when the edit button is clicked.
  • onRowClick - An action to execute when a row is clicked.
  • defaultView - The default view to display in the datagrid.
  • toolbar - An array of toolbar items to display in the datagrid.
  • items - An array of items to display in the datagrid. As alternative to query property.

Columns

The columns object is an array of objects that define the columns in the datagrid. Each object in the columns array has a name property that defines the field name or resolver for the GraphQL query.

Column Properties

  • name - The name of the field or resolver for the GraphQL query.
  • label - An object that contains the labels for the column.
  • editor - An object that defines the editor for the column.
  • showAs - An object that defines how to display the column value.
  • value - Value column. GraphQL query will ignore this column, and the value will be computed from the value property.
  • props.allowOrderBy - Boolean to enable/disable sorting on this column (default: true).
  • props.orderByProperty - Optional property name to use for sorting instead of the column name. Useful when displaying a formatted value but sorting by an underlying field (e.g., display customer name but sort by customer ID).
  • props.allowFilter - Boolean to enable/disable filtering on this column.
  • props.filterByProperty - Optional property name to use for filtering instead of the column name. Alias for filter.fieldName - useful when you don't need a custom filter component.
  • props.filter - Filter configuration object:
    • component - Component to use for the filter input (e.g., custom select, date picker).
    • fieldName - Optional property name to use for filtering instead of the column name (takes precedence over filterByProperty).
    • props - Additional properties passed to the filter component.
  • enableEdit - Boolean to enable inline cell editing for this column.
  • editor - Component config rendered via ComponentRender when enableEdit is true. Uses the same { component, props } pattern as showAs.
  • onEdit - Action array executed sequentially when the cell value changes.

Inline Cell Editing

Enable inline editing of individual cells directly in the DataGrid. Editable columns render their editor component in the cell (always visible, no click-to-toggle). On value change, the onEdit action pipeline executes — typically a GraphQL mutation followed by a notification.

Column Configuration

PropertyTypeDescription
enableEditbooleanEnables inline editing for this column
editor{ component, props }Component rendered via ComponentRender (same pattern as showAs)
onEditaction[]Action array executed sequentially when the value changes

When both showAs and editor (with enableEdit: true) are defined on a column, the editor takes priority for rendering.

Available Variables in onEdit Actions

VariableDescription
{{ changedValues }}The new value after editing
{{ value }}The original value before editing
Row data fieldsAll row data fields (e.g., {{ orderId }}, {{ trackingNumber }})

Example: Editable DateTime Column

columns:
- name: customValues.ETA
label:
en-US: ETA
enableEdit: true
editor:
component: field
props:
type: datetime
onEdit:
- mutation:
command: |
mutation UpdateOrderMutation($input: UpdateOrderInput!) {
updateOrder(input: $input) {
order { orderId }
}
}
variables:
input:
organizationId: "{{number organizationId }}"
orderId: "{{number orderId }}"
values:
customValues:
ETA: "{{ changedValues }}"
onSuccess:
- notification:
message:
en-US: "ETA has been updated to {{ changedValues }}"
showAs:
component: text
props:
value: "{{ format customValues.ETA L }}"
info

showAs is still defined for non-edit contexts (e.g., export, print). When enableEdit: true, the editor renders instead.

Example: Custom Component as Editor

Any component registered in ComponentRender can be used as an editor:

columns:
- name: customValues.returnLocation
label:
en-US: Return Location
enableEdit: true
editor:
component: TRTImport/Terminals/Select
onEdit:
- mutation:
command: |
mutation UpdateOrderMutation($input: UpdateOrderInput!) {
updateOrder(input: $input) {
order { orderId }
}
}
variables:
input:
organizationId: "{{number organizationId }}"
orderId: "{{number orderId }}"
values:
customValues:
returnLocation: "{{ changedValues }}"
onSuccess:
- notification:
message:
en-US: "Return Location has been updated"

Entity Field Integration

Entity fields store enableEdit, editor, and onEdit inside props (the backend entity schema accepts known root-level properties; props is a flexible dictionary):

entities:
- name: TRTImportPickupOrder
fields:
- name: customValues.ETA
displayName:
en-US: ETA
fieldType: enhanced-rangedatetime
props:
enableEdit: true
editor:
component: field
props:
type: datetime
onEdit:
- mutation:
command: |
mutation UpdateOrderMutation($input: UpdateOrderInput!) {
updateOrder(input: $input) {
order { orderId }
}
}
variables:
input:
organizationId: "{{number organizationId }}"
orderId: "{{number orderId }}"
values:
customValues:
ETA: "{{ changedValues }}"
onSuccess:
- notification:
message:
en-US: "ETA has been updated to {{ changedValues }}"

When entity fields are loaded, enableEdit/editor/onEdit are extracted from props and promoted to column-level properties.

How It Works

  1. Rendering: row.tsx checks column.enableEdit && column.editor before showAs. The editor config is passed to ComponentRender.
  2. Form context: When any column has enableEdit: true, the DataGrid automatically wraps content with a React Hook Form FormProvider.
  3. Value flow: Row data → variables.value → Controller defaultValue. User changes trigger handleChange → updates form + dispatches onEdit actions.
  4. Action pipeline: onEdit is a standard action array (same as onClick, dots menu items, etc.). Supports mutation, workflow, notification, navigate, dialog, and more.
  5. Saved views: Edit properties are persisted when saving custom views and merged with original YAML definitions on load.

Editable Options (Prototype Phase)

To enable editing on the datagrid, you need to provide the editableOptions object in the options object and set the enableEdit property to true in the views object.

The editableOptions object has two properties: onRowChange and onRowDelete. Both properties are objects that have a mutation property. The mutation property is a mutation that will be executed when the row is changed or deleted.

Column editors can be defined in the columns object. The editor object is a field component that will be used to edit the column value. The editor object has a type property that defines the type of editor to use.

views:
- name: allCountries
enableEdit: true
columns:
- name: countryCode
label:
en-US: Country code
editor:
# field props for the editor
type: text
editableOptions:
onNewRow: # mutation to create a new record
mutation:
onRowChange: # mutation to update a record
mutation:
onRowDelete: # mutation to delete a record
mutation:

Filter Persistence

By default, the DataGrid persists filter state (both filter column selections and filter values) across route navigation within the same browser session. When a user applies filters on a grid, navigates away, and returns, their filters are automatically restored.

How It Works

Filter state is managed by a singleton Zustand store (gridFilterStore) that lives outside the component tree. Unlike per-page state (which resets on navigation), this store survives route changes because it is not tied to any UiContextProvider.

  • Filter columns (which filter inputs are visible) are persisted when the user adds or removes filter columns, and when view defaults are first applied.
  • Filter values (the actual selected/entered filter criteria) are persisted every time the user changes a filter.
  • On mount, the DataGrid reads any previously persisted state for the current grid + view combination and initializes with those values.

View-Scoped Persistence

Filter state is scoped per grid + view combination using the key format {gridName}:{viewId}. This means switching between views (e.g., "All Orders" vs. "Open Orders") maintains independent filter state for each view. This prevents filters from one view bleeding into another.

Clear Filters

A clear filters button (✕ icon) appears next to the filter bar when filters are active. Clicking it:

  1. Clears all persisted filter state for the current grid + view
  2. Restores the view's original default filters (as defined in the view configuration)
  3. Resets the filter UI to its initial state

Behavior Details

ScenarioBehavior
User sets filters, navigates away, returnsFilters are restored automatically (for that specific view)
User opens grid for the first timeView default filters apply as normal
View has default filter columns, user hasn't customizedDefaults are persisted on first load
User adds/removes filter columnsChanges are persisted immediately
User switches viewsEach view has independent filter state
User clicks clear filters buttonFilters reset to view defaults, persisted state cleared
Page refresh (full reload)Filters reset (store is in-memory only)
info

Filter persistence is in-memory only — it does not survive a full page refresh or new browser tab. It is designed specifically for SPA route navigation within a single session.

Selectable

To enable selection on the datagrid, you need to set the enableSelect property to Single or Multiple in the views object.

When selection is enabled, the selected rows will be available in the gridName.selectedItems property in store.

Child Views

Child views are used to display nested data in the datagrid. The childViews object is an array of objects that define the child views for the datagrid. Each object in the childViews array has a name property that defines the field name or resolver for the GraphQL query.

Styling

The DataGrid component supports conditional styling for rows and columns based on data values, with support for light and dark themes.

Row Styles

Configure row styles using the rowStyles property within each view:

views:
- name: allCountries
rowStyles:
# Conditional styles based on row data
conditions:
- condition: "{{ isEquals item.status 'active' }}"
className: "row-active"
style:
light:
backgroundColor: "#e8f5e9"
borderColor: "#4caf50"
dark:
backgroundColor: "#1b5e20"
borderColor: "#66bb6a"

- condition: "{{ moreThan item.amount 10000 }}"
className: "row-high-value"
style:
light:
backgroundColor: "#fff3e0"
color: "#e65100"
fontWeight: "bold"
dark:
backgroundColor: "#3e2723"
color: "#ffab40"
fontWeight: "bold"

- condition: "{{ eval item.daysOverdue > 30 }}"
className: "row-overdue"
style:
light:
backgroundColor: "#ffebee"
opacity: 0.9
dark:
backgroundColor: "#4a1419"
opacity: 0.9

# Use a field value as className
classNameField: "item.rowStyleClass"

# Style function for complex logic
styleFunction: "{{ eval getRowStyle(item) }}"

Column Styles

Extend column definitions with style properties:

columns:
- name: status
label:
en-US: Status
styles:
# Conditional cell styles
conditions:
- condition: "{{ isEquals value 'completed' }}"
className: "cell-success"
style:
light:
backgroundColor: "#d4edda"
color: "#155724"
borderRadius: "4px"
padding: "4px 8px"
dark:
backgroundColor: "#1e4620"
color: "#82e284"
borderRadius: "4px"
padding: "4px 8px"

- condition: "{{ isEquals value 'pending' }}"
className: "cell-warning"
style:
light:
backgroundColor: "#fff3cd"
color: "#856404"
borderRadius: "4px"
padding: "4px 8px"
dark:
backgroundColor: "#3d2f00"
color: "#ffd54f"
borderRadius: "4px"
padding: "4px 8px"

- condition: "{{ isEquals value 'failed' }}"
className: "cell-danger"
style:
light:
backgroundColor: "#f8d7da"
color: "#721c24"
borderRadius: "4px"
padding: "4px 8px"
dark:
backgroundColor: "#4a1419"
color: "#ff8a95"
borderRadius: "4px"
padding: "4px 8px"

# Column-wide style
className: "column-status"
align: "center" # left, center, right
width: "120px"
minWidth: "80px"
maxWidth: "200px"

Complete Styling Example

component: dataGrid
name: ordersGrid
props:
views:
- name: allOrders
displayName:
en-US: All Orders

# Row styling configuration
rowStyles:
conditions:
- condition: "{{ isEquals item.priority 'urgent' }}"
className: "row-urgent"
style:
light:
backgroundColor: "#ffebee"
borderLeft: "4px solid #f44336"
fontWeight: "600"
dark:
backgroundColor: "#4a1419"
borderLeft: "4px solid #ff5252"
fontWeight: "600"

- condition: "{{ moreThan item.totalAmount 50000 }}"
className: "row-high-value"
style:
light:
backgroundColor: "#e8f5e9"
borderLeft: "4px solid #4caf50"
fontWeight: "600"
dark:
backgroundColor: "#1b5e20"
borderLeft: "4px solid #66bb6a"
fontWeight: "600"

- condition: "{{ moreThan item.daysOverdue 0 }}"
className: "row-overdue"
style:
light:
backgroundColor: "#fff3e0"
borderLeft: "4px solid #ff9800"
opacity: 0.9
dark:
backgroundColor: "#3e2723"
borderLeft: "4px solid #ffab40"
opacity: 0.9

# Date comparison examples
- condition: "{{ moreThan (daysAgo item.dueDate) 0 }}"
className: "row-past-due"
style:
light:
backgroundColor: "#ffcdd2"
borderLeft: "4px solid #d32f2f"
dark:
backgroundColor: "#5d1418"
borderLeft: "4px solid #ff5252"

- condition: "{{ lessThan (daysUntil item.expiryDate) 7 }}"
className: "row-expiring-soon"
style:
light:
backgroundColor: "#fff9c4"
borderLeft: "4px solid #fbc02d"
dark:
backgroundColor: "#3d3200"
borderLeft: "4px solid #ffd54f"

- condition: "{{ moreThan (dateDiff item.actualDate item.plannedDate) 5 }}"
className: "row-delayed"
style:
light:
backgroundColor: "#ffccbc"
borderLeft: "4px solid #d84315"
dark:
backgroundColor: "#3e2723"
borderLeft: "4px solid #ff6e40"

# Column styling configuration
columns:
- name: orderNumber
label:
en-US: Order #
styles:
className: "column-order-number"
align: "center"
style:
light:
fontWeight: "600"
color: "#1976d2"
dark:
fontWeight: "600"
color: "#90caf9"

- name: status
label:
en-US: Status
styles:
align: "center"
conditions:
- condition: "{{ isEquals value 'delivered' }}"
style:
light:
backgroundColor: "#d4edda"
color: "#155724"
borderRadius: "4px"
padding: "4px 8px"
dark:
backgroundColor: "#1e4620"
color: "#82e284"
borderRadius: "4px"
padding: "4px 8px"

- condition: "{{ isEquals value 'pending' }}"
style:
light:
backgroundColor: "#fff3cd"
color: "#856404"
borderRadius: "4px"
padding: "4px 8px"
dark:
backgroundColor: "#3d2f00"
color: "#ffd54f"
borderRadius: "4px"
padding: "4px 8px"

- condition: "{{ isEquals value 'cancelled' }}"
style:
light:
backgroundColor: "#f8d7da"
color: "#721c24"
borderRadius: "4px"
padding: "4px 8px"
dark:
backgroundColor: "#4a1419"
color: "#ff8a95"
borderRadius: "4px"
padding: "4px 8px"

- name: totalAmount
label:
en-US: Total
styles:
align: "right"
width: "150px"
conditions:
- condition: "{{ moreThan value 50000 }}"
style:
light:
color: "#2e7d32"
fontWeight: "600"
dark:
color: "#66bb6a"
fontWeight: "600"
- condition: "{{ moreThan value 100000 }}"
style:
light:
color: "#1b5e20"
fontWeight: "bold"
fontSize: "1.1em"
dark:
color: "#4caf50"
fontWeight: "bold"
fontSize: "1.1em"

options:
query: orders
rootEntityName: Order

Style Properties Reference

Row Style Properties

  • conditions: Array of conditional styles based on row data
  • className: CSS class name to apply
  • classNameField: Field path to get className from row data
  • styleFunction: JavaScript function to compute styles dynamically
  • style: Style object with light and dark theme variants

Column Style Properties

  • conditions: Array of conditional styles based on cell value
  • className: CSS class name for the column
  • align: Text alignment (left, center, right)
  • width: Fixed column width
  • minWidth: Minimum column width
  • maxWidth: Maximum column width
  • style: Style object with light and dark theme variants

Available Style Conditions

  • {{ isEquals item.field 'value' }}: Check equality
  • {{ moreThan item.field 100 }}: Check if greater than
  • {{ lessThan item.field 100 }}: Check if less than
  • {{ isTrue item.field }}: Check boolean value
  • {{ isNullOrEmpty item.field }}: Check null or empty
  • {{ any item.fields }}: Check if any value is true
  • {{ eval expression }}: Evaluate custom JavaScript expression (⚠️ Not recommended due to performance issues)

Date Comparison Functions

  • {{ dateDiff date1 date2 }}: Days between dates (positive if date1 > date2)
  • {{ daysBetween date1 date2 }}: Absolute days between dates
  • {{ daysUntil futureDate }}: Days until future date from now
  • {{ daysAgo pastDate }}: Days since past date until now
  • {{ isDateBefore date1 date2 }}: Check if date1 is before date2
  • {{ isDateAfter date1 date2 }}: Check if date1 is after date2
  • {{ now() }}: Current date for comparisons

Date Styling Examples

# Style if due date has passed
condition: "{{ moreThan (daysAgo item.dueDate) 0 }}"

# Style if expiring within 7 days
condition: "{{ lessThan (daysUntil item.expiryDate) 7 }}"

# Style if delivery is delayed by more than 3 days
condition: "{{ moreThan (dateDiff item.actualDelivery item.plannedDelivery) 3 }}"

# Style if created more than 30 days ago
condition: "{{ moreThan (daysAgo item.createdDate) 30 }}"

Common CSS Properties

  • backgroundColor: Background color
  • color: Text color
  • fontSize: Font size
  • fontWeight: Font weight (normal, bold, 600, etc.)
  • borderLeft, borderRight, borderTop, borderBottom: Border styles
  • borderRadius: Rounded corners
  • padding: Cell padding
  • opacity: Transparency (0-1)
  • textAlign: Text alignment
  • textDecoration: Underline, strikethrough, etc.