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
TypeScript ts
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();
}
Vue vue
<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>
React tsx
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;
Angular ts
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.

| Property | Type | Description | | -------- | ---- | ----------- | | template | (h: Function, data: any) => JSX.Element | A function that returns the JSX structure for the master row. It receives a rendering function h and the data context data. | | allowDetailEvents | readonly 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.


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
  • 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.