Skip to content

Vue 2 Tree Data Grid ​

Vue 2 uses the same free/core tree concept: your component prepares a flat row list with a level field, and RevoGrid renders indentation through a cell template.

INFO

The live core tree demo is available in the Vue 3 wrapper, but the grid data shape and cell-template approach are the same for Vue 2.

Tree-like rows do not require Pro when your application only needs a visual hierarchy. The free/core approach is to flatten parent-child records into display order, add a level field, and render indentation in a cell template.

This keeps RevoGrid simple: the grid receives a normal source array, virtualization still works, and your application owns the hierarchy transformation.

Tree model ​

Start with records that have an ID and a parent ID:

ts
const inputData = [
  { id: 4, parentId: 0, name: 'Antoni father for 2' },
  { id: 5, parentId: 4, name: 'Odin' },
  { id: 6, parentId: 4, name: 'John' },
  { id: 1, parentId: 0, name: 'Mary mother for 2' },
  { id: 2, parentId: 1, name: 'Howard has also 2' },
];

Convert that data into a flat display list before assigning it to the grid:

ts
function buildTreeData(rows: typeof inputData, rootParentId = 0) {
  const childrenByParent = new Map<number, typeof inputData>();

  for (const row of rows) {
    const children = childrenByParent.get(row.parentId) ?? [];
    children.push(row);
    childrenByParent.set(row.parentId, children);
  }

  const result: Array<(typeof inputData)[number] & { level: number }> = [];

  function appendChildren(parentId: number, level = 0) {
    for (const child of childrenByParent.get(parentId) ?? []) {
      result.push({ ...child, level });
      appendChildren(child.id, level + 1);
    }
  }

  appendChildren(rootParentId);
  return result;
}

Indented cell template ​

The core demo uses a normal cell template to show hierarchy depth:

ts
const columns = [
  {
    prop: 'name',
    name: 'Tree',
    size: 300,
    cellTemplate(h, { value, model }) {
      return h(
        'div',
        {
          style: {
            marginLeft: `${(model?.level ?? 0) * 30}px`,
          },
        },
        value || '',
      );
    },
  },
  {
    prop: 'level',
    readonly: true,
  },
];

Use the core approach when the hierarchy is read-only or mostly decorative: category outlines, simple nested lists, document sections, or a tree table where your app handles all expand/collapse logic outside the grid.

Core limits ​

The free/core pattern is intentionally lightweight. It does not add built-in expand/collapse controls, automatic parent-child visibility, tree-aware drag-and-drop, sticky parent rows, or parent/descendant row selection behavior. Those behaviors belong in the Pro Tree Data plugin.

Vue 2 notes ​

  • Build treeData in component data, computed properties, or a store.
  • Replace the source array when the hierarchy changes.
  • Use $refs.grid.$el only when you need direct access to the underlying Web Component.
vue
<revo-grid
  ref="grid"
  :columns="columns"
  :source="treeData"
  readonly
/>

Pro Tree Data ​

RevoGrid Pro adds a dedicated TreeDataPlugin for advanced data grid tree structures. It keeps the original source flat, computes hierarchy metadata internally, and renders tree controls in the column marked with tree: true.

RevoGrid Pro

Use the Pro plugin when hierarchy is not just indentation: users need expand/collapse controls, persistent expansion state, filtering and sorting with hierarchy awareness, row selection across descendants, drag-and-drop reparenting, or sticky parent rows while scrolling long branches.

Pro data model ​

The Pro model also starts from stable IDs and parent IDs:

ts
type TeamRow = {
  id: string;
  parentId: string | null;
  name: string;
  role: string;
  budget: number;
};

const source: TeamRow[] = [
  { id: 'eng', parentId: null, name: 'Engineering', role: 'Department', budget: 850000 },
  { id: 'platform', parentId: 'eng', name: 'Platform', role: 'Team', budget: 320000 },
  { id: 'api', parentId: 'platform', name: 'API', role: 'Squad', budget: 140000 },
  { id: 'design', parentId: null, name: 'Design', role: 'Department', budget: 260000 },
];

Unlike the core example, you do not add level yourself. The plugin derives level, visibility, expanded state, and child metadata from the tree config.

Pro column and plugins ​

Mark one hierarchy column with tree: true, register TreeDataPlugin, and pass the tree config:

ts
import {
  TreeDataPlugin,
  RowOrderPlugin,
  RowSelectPlugin,
  StickyCellsPlugin,
  TREE_EXPAND_ALL_EVENT,
  TREE_COLLAPSE_ALL_EVENT,
} from '@revolist/revogrid-pro';

const columns = [
  {
    prop: 'name',
    name: 'Team',
    size: 300,
    tree: true,
    sortable: true,
    rowSelect: true,
    rowDrag: true,
  },
  { prop: 'role', name: 'Role', size: 160 },
  { prop: 'budget', name: 'Budget', size: 140 },
];

const plugins = [
  TreeDataPlugin,
  RowOrderPlugin,
  RowSelectPlugin,
  StickyCellsPlugin,
];

const tree = {
  idField: 'id',
  parentIdField: 'parentId',
  rootParentId: null,
  expandedRowIds: new Set(['eng']),
  stickyParents: true,
};

Framework wrappers pass these values as props or bindings. Plain TypeScript assigns them to the revo-grid element.

Expand and collapse controls ​

The Pro plugin exposes events for toolbar buttons and external controls:

ts
grid.dispatchEvent(new CustomEvent(TREE_EXPAND_ALL_EVENT));
grid.dispatchEvent(new CustomEvent(TREE_COLLAPSE_ALL_EVENT));

Use expandAll: true when every branch should open on first render. Use expandedRowIds when you want controlled initial state or persisted expansion.

Production guidance ​

  • Keep IDs stable across refreshes so expanded state survives data updates.
  • Use parentId: null or another explicit rootParentId consistently.
  • Keep only one tree column active; use normal columns for the rest of the row data.
  • Combine tree data with virtualization for large hierarchies instead of rendering nested DOM lists.
  • Add StickyCellsPlugin only when sticky parent rows are useful for long branches.
  • Reconcile drag-and-drop changes in your application store before saving to the backend.
  • Prefer flat server payloads for large trees; they are simpler to page, diff, validate, and persist.