Skip to content

Row Selection

Apply selection to rows in grid.

This is an advanced feature that allows users to select multiple rows in grid and explains how to implement this with the help of the RowSelectPlugin.

Selected rows
Source code
TypeScript ts
import { defineCustomElements } from '@revolist/revogrid/loader';
import { currentTheme } from '../composables/useRandomData';
import {
  createRowSelectColumns,
  createRowSelectGrouping,
  createRowSelectOptions,
  createRowSelectTree,
  createRowSelectionSummary,
  createRowSelectionSummaryFromEvent,
  createRowSelectRows,
  formatRowSelectionSummary,
  ROW_SELECT_DEFAULT_MODE,
  ROW_SELECT_MODES,
  ROW_SELECT_PLUGINS,
  ROW_SELECT_ROW_ORDER,
  type RowSelectDemoMode,
} from './row-select-demo.shared';

defineCustomElements();

const { isDark } = currentTheme();

function configureRowSelectGrid(
  grid: HTMLRevoGridElement & {
    rowSelect?: ReturnType<typeof createRowSelectOptions>;
    rowOrder?: typeof ROW_SELECT_ROW_ORDER;
    tree?: ReturnType<typeof createRowSelectTree>;
  },
  summary: HTMLElement | null,
  rows?: any[],
  mode: RowSelectDemoMode = ROW_SELECT_DEFAULT_MODE,
) {
  const source = createRowSelectRows(rows, mode);
  if (summary) {
    summary.textContent = formatRowSelectionSummary(createRowSelectionSummary(source.length));
  }

  grid.className = `${grid.className || ''} grow h-full min-h-0 cell-border`.trim();
  grid.style.minHeight = grid.style.minHeight || '420px';
  grid.theme = isDark() ? 'darkCompact' : 'compact';
  grid.columns = createRowSelectColumns(mode);
  grid.plugins = ROW_SELECT_PLUGINS;
  grid.grouping = createRowSelectGrouping(mode);
  grid.rowSelect = createRowSelectOptions(mode);
  grid.tree = createRowSelectTree(mode);
  grid.rowOrder = ROW_SELECT_ROW_ORDER;
  grid.stretch = 'last';
  grid.hideAttribution = true;
  grid.addEventListener('rowselected', (event: CustomEvent<HTMLRevoGridElementEventMap['rowselected']>) => {
    if (summary) {
      summary.textContent = formatRowSelectionSummary(createRowSelectionSummaryFromEvent(event, source.length));
    }
  });
  grid.source = source;
}

export function load(parentSelector: string, rows?: any[]) {
  const parent = document.querySelector(parentSelector);
  if (!parent) {
    return () => {};
  }

  const shell = document.createElement('div');
  shell.className = 'grow h-full flex flex-col gap-3 min-h-0';

  const toolbar = document.createElement('div');
  toolbar.className = 'flex items-center gap-3 flex-wrap';

  const modeSelect = document.createElement('select');
  modeSelect.className = 'rv-input min-w-36';
  ROW_SELECT_MODES.forEach(({ label, value }) => {
    const option = document.createElement('option');
    option.value = value;
    option.textContent = label;
    option.selected = value === ROW_SELECT_DEFAULT_MODE;
    modeSelect.appendChild(option);
  });

  const summary = document.createElement('div');
  summary.className = 'text-sm font-medium';

  const gridHost = document.createElement('div');
  gridHost.className = 'grow h-full min-h-0 flex';

  toolbar.append(modeSelect, summary);
  shell.append(toolbar, gridHost);
  parent.appendChild(shell);

  const renderGrid = () => {
    gridHost.textContent = '';
    const grid = document.createElement('revo-grid') as HTMLRevoGridElement & {
      rowSelect?: ReturnType<typeof createRowSelectOptions>;
      rowOrder?: typeof ROW_SELECT_ROW_ORDER;
      tree?: ReturnType<typeof createRowSelectTree>;
    };
    gridHost.appendChild(grid);
    configureRowSelectGrid(grid, summary, rows, modeSelect.value as RowSelectDemoMode);
  };

  modeSelect.addEventListener('change', renderGrid);
  renderGrid();

  return () => {
    modeSelect.removeEventListener('change', renderGrid);
    shell.remove();
  };
}

const existingGrid = document.querySelector('revo-grid') as (HTMLRevoGridElement & {
  rowSelect?: ReturnType<typeof createRowSelectOptions>;
  rowOrder?: typeof ROW_SELECT_ROW_ORDER;
  tree?: ReturnType<typeof createRowSelectTree>;
}) | null;
const existingSummary = document.getElementById('selected-rows');
if (existingGrid && existingSummary) {
  configureRowSelectGrid(existingGrid, existingSummary);
}

Key Features

  • Row Selection: Allows users to select multiple rows in the grid.
  • Column Selection: Enables users to select entire columns.
  • Grouped Row Selection: Can render optional group-level checkboxes that select all descendant data rows.
  • Checkbox-Based Row Reorder: Can hand checkbox-selected rows to RowOrderPlugin so checked rows drag as one compact block.
  • Automatic Theme Support: The plugin adapts to light or dark themes based on user settings.
  • Flexible and Extensible: This plugin demonstrates the potential for creating custom plugins, encouraging developers to expand the grid's functionality further.

To enable the RowSelectPlugin in your RevoGrid setup, you have two options:

  1. Using rowSelect Prop in Columns
  2. Using columnType with RowSelectColumnType

In this approach, the rowSelect property in the column definition enables checkbox-based row selection for the specific column.

grid.columns = [
{
prop: '_check',
rowSelect: true,
},
...
];
// Define plugin
grid.plugins = [RowSelectPlugin];

Option 2: Using columnType with RowSelectColumnType

Section titled “Option 2: Using columnType with RowSelectColumnType”

Alternatively, you can use a custom columnType and the RowSelectColumnType to enable row selection.

import { RowSelectColumnType, RowSelectPlugin, DEFAULT_SEL_PROP } from '@revolist/revogrid-pro';
grid.source = [];
// Define columns
grid.columns = [{
prop: DEFAULT_SEL_PROP,
columnType: 'select' // Use columnType 'select'
}, ...];
// Define plugin
grid.plugins = [RowSelectPlugin];
// Define the custom column type for selection
grid.columnTypes = { select: new RowSelectColumnType()};

Grouped row checkboxes are opt-in so existing grouped grids keep their current rendering.

grid.columns = [
{ prop: 'selected', rowSelect: true },
{ prop: 'name', name: 'Name' },
{ prop: 'department', name: 'Department' },
];
grid.grouping = { props: ['department'], expandedAll: true };
grid.rowSelect = {
grouping: true,
};
grid.plugins = [RowSelectPlugin];

You can also use the future-compatible object form:

grid.rowSelect = {
grouping: {
enabled: true,
},
};

When enabled, selecting a group checkbox selects all descendant data rows. Selecting only part of a group reflects an indeterminate state on the group checkbox. Synthetic grouping rows are not included in selected row counts.

RowSelectPlugin can opt into RowOrderPlugin integration. When enabled, dragging a checked row moves all visible checked data rows in the current row viewport as a compact block.

This feature is disabled by default. Existing row-order behavior is unchanged unless rowSelect.rowOrder is enabled.

import { RowOrderPlugin, RowSelectPlugin } from '@revolist/revogrid-pro';
grid.columns = [
{ prop: 'drag', name: '', rowDrag: true, size: 42 },
{ prop: 'selected', name: '', rowSelect: true, size: 56 },
{ prop: 'name', name: 'Name' },
{ prop: 'team', name: 'Team' },
];
grid.rowSelect = {
rowOrder: true,
};
grid.rowOrder = {
prop: 'name',
preview: 'compact',
};
grid.plugins = [RowSelectPlugin, RowOrderPlugin];

You can also use the object form:

grid.rowSelect = {
rowOrder: {
enabled: true,
},
};

Checkbox selection takes priority over range selection only when the dragged row is checked. If the dragged row is not checked, RowOrderPlugin falls back to its current range-selection or single-row behavior.

Only visible checked data rows move during the drag. Rows hidden by filtering, collapsed grouping, or collapsed tree branches remain selected but are not part of that drag operation. Synthetic grouping rows are never moved as selected data rows.

Grouped row checkboxes and checkbox-based row reorder can be enabled together:

grid.grouping = { props: ['team'], expandedAll: true };
grid.rowSelect = {
grouping: true,
rowOrder: true,
};
grid.rowOrder = {
prop: 'name',
preview: 'compact',
};
grid.plugins = [RowSelectPlugin, RowOrderPlugin];

With this setup:

  • Group checkboxes select or clear all descendant data rows.
  • Dragging a checked child row moves visible checked child rows as a compact block.
  • Parent and ancestor group checkboxes reflect child selection with checked or indeterminate state.
  • Group headers are excluded from select-all counts and row-order moved items.
  • Row-order grouping validation still applies, so invalid cross-group drops remain blocked unless your row-order configuration explicitly allows applying target group values.

Filtering, Sorting, Row Drag, And Tree Data

Section titled “Filtering, Sorting, Row Drag, And Tree Data”

Row selection is stored against real data row indexes, not the rendered row position. This keeps checkbox state stable when the visible row topology changes.

| Case | Behavior | | --- | --- | | Filtering | Selected hidden rows remain selected. The rowselected event is re-emitted so visibleCount and visibleRowsCount reflect the filtered view. | | Sorting | Checkbox state follows the same data rows after sort order changes. | | Row drag | Checkbox state follows moved data rows after row order changes. | | Checkbox row-order | When rowSelect.rowOrder is enabled, visible checked rows are moved as a compact block before range selection is considered. | | Grouping | Group checkboxes are opt-in through rowSelect.grouping; synthetic group rows are not counted as selected rows. | | Tree data | When TreeDataPlugin is registered, selecting a tree parent toggles the parent and descendants. Dragging a checkbox-selected tree parent with descendants preserves the subtree relationship. |

| API | Default | Meaning | | --- | --- | --- | | ColumnRegular.rowSelect | false | Renders row-selection checkboxes in normal data cells for that column. A predicate can hide checkboxes for specific cells. | | grid.rowSelect.grouping | false | Enables group-level row-selection checkboxes. Accepts true or { enabled: true }. | | grid.rowSelect.rowOrder | false | Enables checkbox-selected row drag integration with RowOrderPlugin. Accepts true or { enabled: true }. | | additionalData.rowSelect | none | Legacy alias for grid.rowSelect. Prefer direct grid.rowSelect. |

The rowselected event exposes totals for both all selectable rows and the currently visible selectable rows:

| Event field | Meaning | | --- | --- | | count | Selected real data rows across the full dataset. | | allRowsCount | Selectable real data rows across the full dataset. | | visibleCount | Selected real data rows currently visible. | | visibleRowsCount | Selectable real data rows currently visible. |

The live demo on this page is the common Bulk Row Selection example. It includes flat, grouped, and tree modes, a row checkbox column, row drag handles, group checkbox selection, filtering, sorting, selected/visible totals, and opt-in checkbox-based row reorder.