Skip to content

Master Rows

The Master Row Plugin enhances the RevoGrid grid component by enabling the creation and management of master-detail rows. It is an extremely complex and advanced feature, despite its seemingly simple nature. Read more below.

Source code
TypeScriptts
import { defineCustomElements } from '@revolist/revogrid/loader';
import { MasterRowPlugin, CellColumnFocusVerifyPlugin, ColumnStretchPlugin, TreeDataPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';
import { createMasterColumns, masterRowConfig, masterRows, masterTreeConfig } from './rowMasterShared';
import './rowMasterShared.scss';

defineCustomElements();

export function load(parentSelector: string) {
  const grid = document.createElement('revo-grid');
  const { isDark } = currentTheme();

  grid.theme = isDark() ? 'darkMaterial' : 'material';
  grid.columns = createMasterColumns();

  grid.plugins = [
    TreeDataPlugin,
    MasterRowPlugin,
    CellColumnFocusVerifyPlugin,
    ColumnStretchPlugin,
  ];

  Object.assign(grid, {
    masterRow: masterRowConfig,
    tree: masterTreeConfig,
    stretch: 'last',
  });

  document.querySelector(parentSelector)?.appendChild(grid);
  grid.source = masterRows;

  return () => grid.remove();
}
Vuevue
<template>
  <RevoGrid
    class="rounded-lg overflow-hidden"
    :theme="isDark ? 'darkMaterial' : 'material'"
    :source="source"
    :columns="columns"
    :plugins="plugins"
    :master-row.prop="masterRowConfig"
    :tree.prop="masterTreeConfig"
    stretch="last"
    hide-attribution
  />
</template>

<script setup lang="ts">
import RevoGrid from '@revolist/vue3-datagrid';
import './rowMasterShared.scss';
import {
  MasterRowPlugin,
  CellColumnFocusVerifyPlugin,
  ColumnStretchPlugin,
  TreeDataPlugin,
} from '@revolist/revogrid-pro';
import { ref } from 'vue';
import { currentThemeVue } from '../composables/useRandomData';
import { createMasterColumns, masterRowConfig, masterRows, masterTreeConfig } from './rowMasterShared';

const { isDark } = currentThemeVue();

const source = ref(masterRows);

const columns = createMasterColumns();

const plugins = [
  TreeDataPlugin,
  MasterRowPlugin,
  CellColumnFocusVerifyPlugin,
  ColumnStretchPlugin,
];

</script>
Reacttsx
import React, { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import {
  MasterRowPlugin,
  CellColumnFocusVerifyPlugin,
  ColumnStretchPlugin,
  TreeDataPlugin,
} from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';
import { createMasterColumns, masterRowConfig, masterRows, masterTreeConfig } from './rowMasterShared';
import './rowMasterShared.scss';

const { isDark } = currentTheme();

function RowMaster() {
  const source = useMemo(() => masterRows, []);

  const columns = useMemo(() => createMasterColumns(), []);

  const plugins = useMemo(
    () => [
      TreeDataPlugin,
      MasterRowPlugin,
      CellColumnFocusVerifyPlugin,
      ColumnStretchPlugin,
    ],
    [],
  );

  return (
    <RevoGrid
      theme={isDark() ? 'darkMaterial' : 'material'}
      source={source}
      columns={columns}
      plugins={plugins}
      masterRow={masterRowConfig}
      tree={masterTreeConfig}
      stretch="last"
      hideAttribution
    />
  );
}

export default RowMaster;
Angularts
import { Component, ViewEncapsulation, NO_ERRORS_SCHEMA } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import {
  MasterRowPlugin,
  CellColumnFocusVerifyPlugin,
  ColumnStretchPlugin,
  TreeDataPlugin,
} from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';
import { createMasterColumns, masterRowConfig, masterRows, masterTreeConfig } from './rowMasterShared';

@Component({
  selector: 'row-master-grid',
  standalone: true,
  imports: [RevoGrid],
  template: `
    <revo-grid
      [source]="source"
      [columns]="columns"
      [plugins]="plugins"
      [theme]="theme"
      [masterRow]="masterRow"
      [tree]="tree"
      stretch="last"
      [hideAttribution]="true"
      style="min-height: 400px;"
    ></revo-grid>
  `,
  styleUrls: ['./rowMasterShared.scss'],
  encapsulation: ViewEncapsulation.None,
  // Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs.
  schemas: [NO_ERRORS_SCHEMA],
})
export class RowMasterGridComponent {
  source = masterRows;

  columns = createMasterColumns();

  plugins = [
    TreeDataPlugin,
    MasterRowPlugin,
    CellColumnFocusVerifyPlugin,
    ColumnStretchPlugin,
  ];

  theme = currentTheme().isDark() ? 'darkMaterial' : 'material';

  masterRow = masterRowConfig;

  tree = masterTreeConfig;
}

  • Expandable Rows: Easily expand rows to reveal additional details.
  • Custom Templates: Define how master rows are rendered using customizable templates.

  1. Import Necessary Plugins and Utilities:

    import { EXPAND_COLUMN, MasterRowPlugin, CellColumnFocusVerifyPlugin } from '@revolist/revogrid-pro';
    import type { RowMasterConfig } from '@revolist/revogrid';
    import './row-master.style.css';
  2. Define Columns:

    const columns: HTMLRevoGridElement['columns'] = [
    {
    prop: 'expand',
    ...EXPAND_COLUMN,
    },
    // ...
    ];
  3. Initialize the Grid with Plugins:

    const grid = document.querySelector('revo-grid');
    grid.source = makeData(10, 20);
    grid.columns = columns;
    // Define plugin
    grid.plugins = [
    MasterRowPlugin,
    ];
    const masterRow: RowMasterConfig = {
    rowHeight: 100,
    template: (h, data) => {
    return data.model.subRows?.map((subRow: Person) =>
    h('span', { class: { 'master-row': true } }, [
    h('img', { src: subRow.avatar, width: '20', height: '20' }),
    `${subRow.firstName} ${subRow.lastName} `,
    ]),
    );
    },
    };
    grid.masterRow = masterRow;
    }

The Master Row Plugin can be customized by assigning a RowMasterConfig object to grid.masterRow. The primary configuration option is the template function, which defines how the master row content is rendered.

PropertyTypeDescription
template(h: Function, data: any) => JSX.ElementA function that returns the JSX structure for the master row. It receives a rendering function h and the data context data.
allowDetailEventsreadonly string[]Event names from the master detail area that are allowed to bubble to the parent grid. All RevoGrid events inside the detail area are stopped by default.

Customize the master row by defining a template function that returns the desired JSX structure. This allows for flexible and dynamic rendering based on the row data.

const masterRow: RowMasterConfig = {
template: (h, data) => {
return data.model.subRows?.map((subRow: Person) =>
h('div', { class: { 'custom-master-row': true } }, [
h('img', { src: subRow.avatar, width: '30', height: '30' }),
`${subRow.firstName} ${subRow.lastName}`,
]),
);
},
};

To let selected events from nested detail content reach the parent grid, add them by name:

const masterRow: RowMasterConfig = {
allowDetailEvents: ['afteredit'],
template: (h, data) => h('revo-grid', { source: data.model.details }),
};

EXPAND_COLUMN toggles a single master row by dispatching the ROW_MASTER event with the current cell template payload. You can dispatch the same event directly when a toolbar, external control, or custom cell template needs to control master-row state.

For one row, pass the same cell template payload shape used by cell templates. The plugin treats this as a toggle:

import { ROW_MASTER } from '@revolist/revogrid-pro';
grid.dispatchEvent(new CustomEvent(ROW_MASTER, {
detail: cellTemplateData,
}));

For multiple rows, pass a batch payload with a rows array. Each row target declares its desired final state with expanded: true or expanded: false, so one event can open and close different rows at the same time:

import { ROW_MASTER } from '@revolist/revogrid-pro';
import type { RowMasterBatchEvent } from '@revolist/revogrid-pro';
const detail: RowMasterBatchEvent = {
rows: [
{ rowType: 'rgRow', rowIndex: 1, expanded: true },
{ rowType: 'rgRow', rowIndex: 3, expanded: false },
{ rowType: 'rowPinStart', rowIndex: 0, expanded: true },
],
};
grid.dispatchEvent(new CustomEvent(ROW_MASTER, { detail }));

rowIndex is the current virtual row index for the given rowType. The plugin converts every target to a stable internal row reference before applying the batch, so one event can safely mix opened and closed rows without later changes shifting earlier targets. If multiple targets resolve to the same row, the last entry wins.

Expanded master rows are cleared when the grid is about to change row visibility or row structure in a way that can invalidate the detail overlay position.

The plugin calls its internal clearAllRows() cleanup when:

  • the grid source is replaced
  • filtering is about to trim rows through beforefiltertrimmed
  • row dragging starts

During that cleanup, expanded master rows are collapsed, detail overlay nodes are removed, duplicated detail rows are removed from the row item lists, and custom detail row heights are cleared. This prevents a filtered or replaced row from leaving stale detail height behind after the row itself is no longer visible.

To stop this automatic cleanup for one of these moments, listen for BEFORE_ROW_MASTER_COLLAPSE and call preventDefault():

import { BEFORE_ROW_MASTER_COLLAPSE } from '@revolist/revogrid-pro';
grid.addEventListener(BEFORE_ROW_MASTER_COLLAPSE, (event) => {
if (event.detail.reason === 'filter') {
event.preventDefault();
}
});

The event detail includes reason ('source', 'filter', or 'drag') and rows, the expanded master rows that are about to be cleared.

Preventing the default cleanup means your application is responsible for handling any stale detail overlays or custom row heights if the related source row is no longer visible.


A plugin class that manages master-detail rows within the RevoGrid component.

  • constructor(revogrid: HTMLRevoGridElement, providers: PluginProviders)

    Initializes the plugin with the RevoGrid instance and plugin providers.

  • expandRow(type: DimensionRows, virtRowIndex: number)

    Expands a specific row to show its master details.

  • collapseRow(type: DimensionRows, rowVIndexes: number[])

    Collapses one or more rows, hiding their master details.

  • destroy()

    Cleans up event listeners and other resources when the plugin is destroyed.

The plugin listens to various RevoGrid events to manage the state of master rows, including:

  • AFTER_GRID_RENDER_EVENT
  • BEFORE_ROW_RENDER_EVENT
  • BEFORE_ROW_MASTER_COLLAPSE - cancelable event fired before automatic master-row cleanup collapses expanded rows.
  • ROW_MASTER - toggles one row from a cell template payload, or applies a batch of desired row states with { rows: [{ rowType, rowIndex, expanded }] }.
  • OVERLAY_NODE
  • …and more.