Checkbox Selection in Vue TreeGrid

30 Sep 202624 minutes to read

Checkbox Selection provides an option to select multiple TreeGrid records with help of checkbox in each row.

To render checkbox in each treegrid row, you need to use checkbox column with type as CheckBox using
column type property.

<template>
<div id="app">
        <ejs-treegrid ref='treegrid' :dataSource='data' childMapping='subtasks' :treeColumnIndex='2'>
            <e-columns>
                <e-column type='checkbox' width='50'></e-column>
                <e-column field='taskID' headerText='Task ID' width='90' textAlign='Right'></e-column>
                <e-column field='taskName' headerText='Task Name' width='160'></e-column>
                <e-column field='startDate' headerText='Start Date' width='90' format="yMd" textAlign='Right'></e-column>
                <e-column field='duration' headerText='Duration' width='80' textAlign='Right'></e-column>
            </e-columns>
        </ejs-treegrid>
</div>
</template>
<script setup>
import { provide } from "vue";

import { TreeGridComponent as EjsTreegrid,  Page, ColumnDirective as EColumn, ColumnsDirective as EColumns } from "@syncfusion/ej2-vue-treegrid";
import { sampleData } from "./datasource.js";

const data = sampleData;

provide('treegrid',  [ Page ]);

</script>
<template>
<div id="app">
        <ejs-treegrid ref='treegrid' :dataSource='data' childMapping='subtasks' :treeColumnIndex='2'>
            <e-columns>
                <e-column type='checkbox' width='50'></e-column>
                <e-column field='taskID' headerText='Task ID' width='90' textAlign='Right'></e-column>
                <e-column field='taskName' headerText='Task Name' width='160'></e-column>
                <e-column field='startDate' headerText='Start Date' width='90' format="yMd" textAlign='Right'></e-column>
                <e-column field='duration' headerText='Duration' width='80' textAlign='Right'></e-column>
            </e-columns>
        </ejs-treegrid>
</div>
</template>
<script>

import { TreeGridComponent,  Page, ColumnDirective, ColumnsDirective } from "@syncfusion/ej2-vue-treegrid";
import { sampleData } from "./datasource.js";

export default {
name: "App",
components: {
"ejs-treegrid":TreeGridComponent,
"e-columns":ColumnsDirective,
"e-column":ColumnDirective,

},

  data ()  {
    return {
      data: sampleData,
    };
  },
  provide: {
      treegrid: [ Page ]
  }
}
</script>

By default selection is allowed by clicking a treegrid row or checkbox in that row. To allow Selection only through checkbox, you can set
selectionSettings.checkboxOnly property to true.
Selection can be persisted on all the operations
using selectionSettings.persistSelection property.
For persisting selection on the TreeGrid, any one of the column should be defined as a primary key
using columns.isPrimaryKey property.

Checkbox selection mode

In checkbox selection, selection can also be done by clicking on rows. This selection provides two types of Checkbox Selection mode which can be set by using the following API
selectionSettings.checkboxMode. The modes are:

  • Default: This is the default value of the checkboxMode. In this mode, user can select multiple rows by clicking rows one by one.
  • ResetOnRowClick: In ResetOnRowClick mode, when user clicks on a row it will reset previously selected row. Also you can perform multiple-selection in this mode by press and hold CTRL key and click the desired rows. To select range of rows, press and hold the SHIFT key and click the rows.
<template>
<div id="app">
        <ejs-treegrid ref='treegrid' :dataSource='data' childMapping='subtasks' :treeColumnIndex='2'
        :selectionSettings='selectionOptions'>
            <e-columns>
                <e-column type='checkbox' width='50'></e-column>
                <e-column field='taskID' headerText='Task ID' width='90' textAlign='Right'></e-column>
                <e-column field='taskName' headerText='Task Name' width='160'></e-column>
                <e-column field='startDate' headerText='Start Date' width='90' format="yMd" textAlign='Right'></e-column>
                <e-column field='duration' headerText='Duration' width='80' textAlign='Right'></e-column>
            </e-columns>
        </ejs-treegrid>
</div>
</template>
<script setup>
import { provide } from "vue";

import { TreeGridComponent as EjsTreegrid,  Page, ColumnDirective as EColumn, ColumnsDirective as EColumns } from "@syncfusion/ej2-vue-treegrid";
import { sampleData } from "./datasource.js";

const data = sampleData;

const selectionOptions = { checkboxMode: 'ResetOnRowClick' };

provide('treegrid',  [ Page ]);

</script>
<template>
<div id="app">
        <ejs-treegrid ref='treegrid' :dataSource='data' childMapping='subtasks' :treeColumnIndex='2'
        :selectionSettings='selectionOptions'>
            <e-columns>
                <e-column type='checkbox' width='50'></e-column>
                <e-column field='taskID' headerText='Task ID' width='90' textAlign='Right'></e-column>
                <e-column field='taskName' headerText='Task Name' width='160'></e-column>
                <e-column field='startDate' headerText='Start Date' width='90' format="yMd" textAlign='Right'></e-column>
                <e-column field='duration' headerText='Duration' width='80' textAlign='Right'></e-column>
            </e-columns>
        </ejs-treegrid>
</div>
</template>
<script>

import { TreeGridComponent,  Page, ColumnDirective, ColumnsDirective } from "@syncfusion/ej2-vue-treegrid";
import { sampleData } from "./datasource.js";

export default {
name: "App",
components: {
"ejs-treegrid":TreeGridComponent,
"e-columns":ColumnsDirective,
"e-column":ColumnDirective,

},

  data ()  {
    return {
      data: sampleData,
      selectionOptions: { checkboxMode: 'ResetOnRowClick'}
    };
  },
  provide: {
      treegrid: [ Page ]
  }
}
</script>

Checkbox Selection feature is intended for row selection only; it is not compatible with cell selection mode.

Conditional row selection

The TreeGrid supports conditional row selection through the isRowSelectable callback. This allows selection to be controlled by custom business logic, ensuring that only rows meeting specific conditions can be selected. The callback receives each row’s data and returns “true” to allow selection or “false” to prevent it.

Local data: The callback runs once when the TreeGrid initializes and evaluates all records because the full dataset is already available on the client.

Remote data: The callback runs only for the rows displayed on the current page when the TreeGrid first loads. It runs again whenever the TreeGrid fetches new data such as during paging, filtering, or sorting to re-evaluate the newly visible rows.

In the following sample, selection is disabled for rows where the “Progress” column has the value “Completed”.

<template>
  <div id="app">
    <ejs-treegrid
      :dataSource="data"
      idMapping="TaskID"
      parentIdMapping="ParentID"
      :treeColumnIndex="1"
      :enableVirtualization="true"
      :selectionSettings="selectionOptions"
      :isRowSelectable="isRowSelectable"
      :height="600"
    >
    <e-columns>
      <e-column type="checkbox" width= '90'></e-column>
      <e-column field='Task' headerText='Task' width='300'></e-column>
      <e-column field='TaskID' isPrimaryKey="true" visible="false"></e-column>
      <e-column field='AssignedTo' headerText='Assigned To' width= '140'></e-column>
      <e-column field='StartDate' headerText='Start' format='yMd' width= '180'></e-column>
      <e-column field='DueDate' headerText='Due' format='yMd' width= '180'></e-column>
      <e-column field='Priority' headerText='Priority' width= '90'></e-column>
      <e-column field='Progress' headerText='Progress' width= '110'></e-column>
    </e-columns>
    </ejs-treegrid>
  </div>
</template>

<script setup>
import { ref, provide } from 'vue';
import {
  TreeGridComponent,
  VirtualScroll,
} from '@syncfusion/ej2-vue-treegrid';
import { taskData } from './data-source';
import { TreeGridComponent as EjsTreegrid, ColumnDirective as EColumn, ColumnsDirective as EColumns,
} from "@syncfusion/ej2-vue-treegrid";

const data = ref(taskData);

const selectionOptions = ref({
  persistSelection: true,
});

const isRowSelectable = (data, columns) => {
  return data.Progress !== 'Completed';
};

provide('treegrid', [VirtualScroll]);
</script>
<template>
<div id="app">
  <ejs-treegrid :dataSource='data' idMapping='TaskID' parentIdMapping='ParentID' :treeColumnIndex='1'
    :enableVirtualization="true" :selectionSettings='selectionOptions' :isRowSelectable="isRowSelectable"
    :height="600">
    <e-columns>
      <e-column type="checkbox" width= '90'></e-column>
      <e-column field='Task' headerText='Task' width='300'></e-column>
      <e-column field='TaskID' isPrimaryKey="true" visible="false"></e-column>
      <e-column field='AssignedTo' headerText='Assigned To' width= '140'></e-column>
      <e-column field='StartDate' headerText='Start' format='yMd' width= '180'></e-column>
      <e-column field='DueDate' headerText='Due' format='yMd' width= '180'></e-column>
      <e-column field='Priority' headerText='Priority' width= '90'></e-column>
      <e-column field='Progress' headerText='Progress' width= '110'></e-column>
    </e-columns>
  </ejs-treegrid>
</div>
</template>
<script>

import { TreeGridComponent, VirtualScroll, ColumnDirective, ColumnsDirective } from "@syncfusion/ej2-vue-treegrid";
import { taskData } from "./datasource.js";

export default {
name: "App",
components: {
  "ejs-treegrid": TreeGridComponent,
  "e-columns": ColumnsDirective,
  "e-column": ColumnDirective,

},

data() {
  return {
    data: taskData,
    selectionOptions: { persistSelection: true }
  };
},
provide: {
  treegrid: [VirtualScroll]
},
methods: {
  isRowSelectable(data, columns) {
    return data.Progress !== 'Completed';
  }
}
}
</script>

Hierarchy checkbox selection

The hierarchy checkbox enables cascading selection of parent and child rows in Tree Grid. When a parent row checkbox is selected, all its child records are automatically selected, and the parent state updates based on children selection. To enable hierarchy checkbox selection, set the showCheckbox property to true in a column and configure the hierarchyCheckboxMode property. By default, hierarchy checkbox mode is set to self.

The available modes are displayed in the following table.

Item Description
self Only the targeted row is selected; children and parent are not affected.
hierarchy Selection cascades to all descendants and adjusts the parent state accordingly.
filteredHierarchy Behaves like hierarchy, but applies the cascade only to records matching the current filter or search criteria.
<template>
    <div class="control-section">
        <div class="content-wrapper">
            <div class="checkboxprop">
                <div class="checkboxmode">
                    <span> Hierarchy Checkbox Mode </span>
                    <div class="checkboxmode">
                        <ejs-dropdownlist id="hierarchyModes" width="180px" :dataSource="hierarchyModeData"
                            :fields="hierarchyModeFields" value="Self" :change="hierarchyModeChange"
                            :htmlAttributes="dropDownAttributes">
                        </ejs-dropdownlist>
                    </div>
                </div>
            </div>
            <div id="app">
            <ejs-treegrid id="TreeGrid" aria-label="Tree Grid" :dataSource="data" childMapping="subTasks"
                :treeColumnIndex="1" :toolbar="toolbarOptions" :allowFiltering="true" :height="380"
                :hierarchyCheckboxMode="hierarchyCheckboxMode" :editSettings='editSettings'
                :queryCellInfo="queryCellInfo">
                <e-columns>
                    <e-column field="taskID" :visible="false" :isPrimaryKey="true"> </e-column>
                    <e-column field="taskName" headerText="Task Name" width="270" :showCheckbox="true">
                    </e-column>
                    <e-column field="assignee" headerText="Employee" width="180">
                    </e-column>
                    <e-column field="designation" headerText="Designation" width="220">
                    </e-column>
                    <e-column field="priority" headerText="Priority" width="140">
                    </e-column>
                    <e-column field="status" headerText="Status" width="120" textAlign="Center">
                    </e-column>
                    <e-column field="progress" headerText="Progress" width="120" textAlign="Right">
                    </e-column>
                </e-columns>
            </ejs-treegrid>
            </div>
        </div>
    </div>
</template>

<script setup>
import { ref, provide } from 'vue';
import {
    TreeGridComponent as EjsTreegrid,
    Filter,
    Toolbar,
    Edit,
    ColumnDirective as EColumn,
    ColumnsDirective as EColumns
} from '@syncfusion/ej2-vue-treegrid';
import { DropDownListComponent as EjsDropdownlist } from '@syncfusion/ej2-vue-dropdowns';
import { QueryCellInfoEventArgs } from '@syncfusion/ej2-grids';
import { showCheckBoxData } from './datasource';

const data = showCheckBoxData;
const editSettings = { allowDeleting: true };
const toolbarOptions = ['Search', 'Delete'];
const hierarchyCheckboxMode = ref('self');
const hierarchyModeData = [
    { id: 'Self', name: 'Self' },
    { id: 'Hierarchy', name: 'Hierarchy' },
    { id: 'FilteredHierarchy', name: 'Filtered Hierarchy' }
];
const hierarchyModeFields = { text: 'name', value: 'id' };
const dropDownAttributes = { tabindex: '1' };

const hierarchyModeChange = (args) => {
    if (args.value === 'Hierarchy') {
        hierarchyCheckboxMode.value = 'hierarchy';
    } else if (args.value === 'FilteredHierarchy') {
        hierarchyCheckboxMode.value = 'filteredHierarchy';
    } else {
        hierarchyCheckboxMode.value = 'self';
    }
};

const queryCellInfo = (args) => {
    if ((args.column && args.column.field !== 'status') ||
        !args.cell || !args.data) {
        return;
    }
    const task = args.data;
    const statusClass = task.status
        .toLowerCase()
        .replace(/\s+/g, '-');
    args.cell.innerHTML = `
        <span class="status-badge ${statusClass}">
        ${task.status}
        </span>
    `;
};

provide('treegrid', [Filter, Toolbar, Edit]);
</script>

<style scoped>
.e-bigger.bootstrap5 .e-treegrid .e-hierarchycheckbox .e-frame,
.e-bigger.bootstrap5-dark .e-treegrid .e-hierarchycheckbox .e-frame,
.e-bigger.bootstrap4 .e-treegrid .e-hierarchycheckbox .e-frame {
    height: 17px;
    width: 17px;
}

.checkboxprop {
    padding-bottom: 5px;
}

.checkboxmode {
    display: inline-block;
}

.checkboxprop>.checkboxmode {
    display: flex;
    align-items: center;
    gap: 12px;
}

.checkboxprop>.checkboxmode>span {
    white-space: nowrap;
}

.checkboxprop>.checkboxmode>.checkboxmode {
    flex: 0 0 180px;
    width: 180px;
}

.status-badge {
    padding: 4px 10px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 600;
    display: inline-block;
}

.completed {
    background: #dcfce7;
    color: #15803d;
}

.in-progress {
    background: #dbeafe;
    color: #1d4ed8;
}

.not-started {
    background: #f3f4f6;
    color: #4b5563;
}

.under-review {
    background: #fef3c7;
    color: #b45309;
}

.blocked {
    background: #fee2e2;
    color: #dc2626;
}
</style>
<template>
    <div class="control-section">
        <div class="content-wrapper">
            <div class="checkboxprop">
                <div class="checkboxmode">
                    <span> Hierarchy Checkbox Mode </span>
                    <div class="checkboxmode">
                        <ejs-dropdownlist id="hierarchyModes" width="180px" :dataSource="hierarchyModeData"
                            :fields="hierarchyModeFields" value="Self" :change="hierarchyModeChange"
                            :htmlAttributes="dropDownAttributes">
                        </ejs-dropdownlist>
                    </div>
                </div>
            </div>
            <div id="app">
            <ejs-treegrid id="TreeGrid" aria-label="Tree Grid" :dataSource="data" childMapping="subTasks"
                :treeColumnIndex="1" :toolbar="toolbarOptions" :allowFiltering="true" :height="380"
                :hierarchyCheckboxMode="hierarchyCheckboxMode" :editSettings='editSettings'
                :queryCellInfo="queryCellInfo">
                <e-columns>
                    <e-column field="taskID" :visible="false" :isPrimaryKey="true"> </e-column>
                    <e-column field="taskName" headerText="Task Name" width="270" :showCheckbox="true">
                    </e-column>
                    <e-column field="assignee" headerText="Employee" width="180">
                    </e-column>
                    <e-column field="designation" headerText="Designation" width="220">
                    </e-column>
                    <e-column field="priority" headerText="Priority" width="140">
                    </e-column>
                    <e-column field="status" headerText="Status" width="120" textAlign="Center">
                    </e-column>
                    <e-column field="progress" headerText="Progress" width="120" textAlign="Right">
                    </e-column>
                </e-columns>
            </ejs-treegrid>
            </div>
        </div>
    </div>
</template>
<style>
.e-bigger.bootstrap5 .e-treegrid .e-hierarchycheckbox .e-frame,
.e-bigger.bootstrap5-dark .e-treegrid .e-hierarchycheckbox .e-frame,
.e-bigger.bootstrap4 .e-treegrid .e-hierarchycheckbox .e-frame {
    height: 17px;
    width: 17px;
}

.checkboxprop {
    padding-bottom: 5px;
}

.checkboxmode {
    display: inline-block;
}

.checkboxprop>.checkboxmode {
    display: flex;
    align-items: center;
    gap: 12px;
}

.checkboxprop>.checkboxmode>span {
    white-space: nowrap;
}

.checkboxprop>.checkboxmode>.checkboxmode {
    flex: 0 0 180px;
    width: 180px;
}

.status-badge {
    padding: 4px 10px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 600;
    display: inline-block;
}

.completed {
    background: #dcfce7;
    color: #15803d;
}

.in-progress {
    background: #dbeafe;
    color: #1d4ed8;
}

.not-started {
    background: #f3f4f6;
    color: #4b5563;
}

.under-review {
    background: #fef3c7;
    color: #b45309;
}

.blocked {
    background: #fee2e2;
    color: #dc2626;
}
</style>
<script>
import { defineComponent } from 'vue';
import {
    ColumnDirective,
    ColumnsDirective,
    Filter,
    Toolbar,
    Edit,
    TreeGridComponent
} from '@syncfusion/ej2-vue-treegrid';
import { DropDownListComponent } from '@syncfusion/ej2-vue-dropdowns';

import { QueryCellInfoEventArgs} from '@syncfusion/ej2-grids';
import { showCheckBoxData} from './datasource';
export default defineComponent({
    components: {
        'ejs-treegrid': TreeGridComponent,
        'e-columns': ColumnsDirective,
        'e-column': ColumnDirective,
        'ejs-dropdownlist': DropDownListComponent
    },
    data() {
        return {
            data: showCheckBoxData,
            editSettings: { allowDeleting: true },
            toolbarOptions: ['Search', 'Delete'],
            hierarchyCheckboxMode:
                'self',
            hierarchyModeData: [
                {
                    id: 'Self',
                    name: 'Self'
                },
                {
                    id: 'Hierarchy',
                    name: 'Hierarchy'
                },
                {
                    id: 'FilteredHierarchy',
                    name: 'Filtered Hierarchy'
                }
            ],
            hierarchyModeFields: {
                text: 'name',
                value: 'id'
            },
            dropDownAttributes: {
                tabindex: '1'
            }
        };
    },
    methods: {
        hierarchyModeChange( args ){
            if (args.value === 'Hierarchy') {
                this.hierarchyCheckboxMode = 'hierarchy';
            } else if (
                args.value === 'FilteredHierarchy'
            ) {
                this.hierarchyCheckboxMode =
                    'filteredHierarchy';
            } else {
                this.hierarchyCheckboxMode = 'self';
            }
        },
        queryCellInfo(args){
            if ((args.column && args.column.field !== 'status') ||
                !args.cell || !args.data) {
                return;
            }
            const task = args.data;
            const statusClass = task.status
                .toLowerCase()
                .replace(/\s+/g, '-');
            args.cell.innerHTML = `
                <span class="status-badge ${statusClass}">
                ${task.status}
                </span>
            `;
        }
    },
    provide: {
        treegrid: [
            Filter,
            Toolbar,
            Edit
        ]
    }
});
</script>