Column spanning in Vue TreeGrid

The column spanning feature in the Syncfusion® Vue TreeGrid allows merging adjacent cells horizontally, creating a visually appealing and informative layout. By defining the colSpan attribute in the queryCellInfo event, cells can be easily spanned and the appearance of the TreeGrid can be customized.

In the following example, Employee Davolio is scheduled for analysis from “9.00 AM” to “10.00 AM”, so those cells have been spanned.

<template>
  <div id="app">
    <ejs-treegrid
      :dataSource="data"
      :treeColumnIndex="1"
      childMapping="subtasks"
      height="auto"
      width="auto"
      gridLines="Both"
      queryCellInfo="queryCellInfoEvent"
    >
      <e-columns>
        <e-column
          field="EmployeeID"
          headerText="Employee ID"
          width="150"
          textAlign="Right"
          :isPrimaryKey="true"
        ></e-column>
        <e-column
          field="EmployeeName"
          headerText="Employee Name"
          width="200"
        ></e-column>
        <e-column field="9:00" headerText="9:00 AM" width="120"></e-column>
        <e-column field="9:30" headerText="9:30 AM" width="120"></e-column>
        <e-column field="10:00" headerText="10:00 AM" width="120"></e-column>
        <e-column field="10:30" headerText="10:30 AM" width="120"></e-column>
        <e-column field="11:00" headerText="11:00 AM" width="120"></e-column>
        <e-column field="11:30" headerText="11:30 AM" width="120"></e-column>
        <e-column field="12:00" headerText="12:00 PM" width="120"></e-column>
        <e-column field="12:30" headerText="12:30 PM" width="120"></e-column>
        <e-column field="2:30" headerText="2:30 PM" width="120"></e-column>
        <e-column field="3:00" headerText="3:00 PM" width="120"></e-column>
        <e-column field="3:30" headerText="3:30 PM" width="120"></e-column>
        <e-column field="4:00" headerText="4:00 PM" width="120"></e-column>
        <e-column field="4:30" headerText="4:30 PM" width="120"></e-column>
        <e-column field="5:00" headerText="5:00 PM" width="120"></e-column>
      </e-columns>
    </ejs-treegrid>
  </div>
</template>
<script setup>

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

const data = columnSpanData;

const queryCellInfoEvent: function (args) {
      let data = args.data;
      switch (data.EmployeeID) {
        case 10001:
          if (
            args.column.field === "9:00" ||
            args.column.field === "2:30" ||
            args.column.field === "4:30"
          ) {
            args.colSpan = 2;
          } else if (args.column.field === "11:00") {
            args.colSpan = 3;
          }
          break;
        case 10002:
          if (
            args.column.field === "9:30" ||
            args.column.field === "2:30" ||
            args.column.field === "4:30"
          ) {
            args.colSpan = 3;
          } else if (args.column.field === "11:00") {
            args.colSpan = 4;
          }
          break;
        case 10003:
          if (args.column.field === "9:00" || args.column.field === "11:30") {
            args.colSpan = 3;
          } else if (
            args.column.field === "10:30" ||
            args.column.field === "3:30" ||
            args.column.field === "4:30" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 2;
          }
          break;
        case 10004:
          if (args.column.field === "9:00") {
            args.colSpan = 3;
          } else if (args.column.field === "11:00") {
            args.colSpan = 4;
          } else if (
            args.column.field === "4:00" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 2;
          }
          break;
        case 10005:
          if (args.column.field === "9:00") {
            args.colSpan = 4;
          } else if (args.column.field === "11:30") {
            args.colSpan = 3;
          } else if (
            args.column.field === "3:30" ||
            args.column.field === "4:30" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 2;
          }
          break;
        case 10006:
          if (
            args.column.field === "9:00" ||
            args.column.field === "4:30" ||
            args.column.field === "2:30" ||
            args.column.field === "3:30"
          ) {
            args.colSpan = 2;
          } else if (
            args.column.field === "10:00" ||
            args.column.field === "11:30"
          ) {
            args.colSpan = 3;
          }
          break;
        case 10007:
          if (
            args.column.field === "9:00" ||
            args.column.field === "3:00" ||
            args.column.field === "10:30"
          ) {
            args.colSpan = 2;
          } else if (
            args.column.field === "11:30" ||
            args.column.field === "4:00"
          ) {
            args.colSpan = 3;
          }
          break;
        case 10008:
          if (
            args.column.field === "9:00" ||
            args.column.field === "10:30" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 3;
          } else if (args.column.field === "4:00") {
            args.colSpan = 2;
          }
          break;
        case 10009:
          if (args.column.field === "9:00" || args.column.field === "11:30") {
            args.colSpan = 3;
          } else if (
            args.column.field === "4:30" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 2;
          }
          break;
        case 100010:
          if (
            args.column.field === "9:00" ||
            args.column.field === "2:30" ||
            args.column.field === "4:00" ||
            args.column.field === "11:30"
          ) {
            args.colSpan = 3;
          } else if (args.column.field === "10:30") {
            args.colSpan = 2;
          }
          break;
      }
    };
</script>
<template>
  <div id="app">
    <ejs-treegrid
      :dataSource="data"
      :treeColumnIndex="1"
      childMapping="subtasks"
      height="auto"
      width="auto"
      gridLines="Both"
      :queryCellInfo="queryCellInfoEvent"
    >
      <e-columns>
        <e-column
          field="EmployeeID"
          headerText="Employee ID"
          width="150"
          textAlign="Right"
          isPrimaryKey="{true}"
        ></e-column>
        <e-column
          field="EmployeeName"
          headerText="Employee Name"
          width="200"
        ></e-column>
        <e-column field="9:00" headerText="9:00 AM" width="120"></e-column>
        <e-column field="9:30" headerText="9:30 AM" width="120"></e-column>
        <e-column field="10:00" headerText="10:00 AM" width="120"></e-column>
        <e-column field="10:30" headerText="10:30 AM" width="120"></e-column>
        <e-column field="11:00" headerText="11:00 AM" width="120"></e-column>
        <e-column field="11:30" headerText="11:30 AM" width="120"></e-column>
        <e-column field="12:00" headerText="12:00 PM" width="120"></e-column>
        <e-column field="12:30" headerText="12:30 PM" width="120"></e-column>
        <e-column field="2:30" headerText="2:30 PM" width="120"></e-column>
        <e-column field="3:00" headerText="3:00 PM" width="120"></e-column>
        <e-column field="3:30" headerText="3:30 PM" width="120"></e-column>
        <e-column field="4:00" headerText="4:00 PM" width="120"></e-column>
        <e-column field="4:30" headerText="4:30 PM" width="120"></e-column>
        <e-column field="5:00" headerText="5:00 PM" width="120"></e-column>
      </e-columns>
    </ejs-treegrid>
  </div>
</template>
<script>

import {
  TreeGridComponent,
  ColumnsDirective,
  ColumnDirective,
} from "@syncfusion/ej2-vue-treegrid";
import { columnSpanData } from "./datasource.js";
export default {
  name: "App",
  components: {
    "ejs-grid": TreeGridComponent,
    "e-columns": ColumnsDirective,
    "e-column": ColumnDirective,
  },
  data: () => {
    return {
      data: columnSpanData,
    };
  },
  methods: {
    queryCellInfoEvent: function (args) {
      let data = args.data;
      switch (data.EmployeeID) {
        case 10001:
          if (
            args.column.field === "9:00" ||
            args.column.field === "2:30" ||
            args.column.field === "4:30"
          ) {
            args.colSpan = 2;
          } else if (args.column.field === "11:00") {
            args.colSpan = 3;
          }
          break;
        case 10002:
          if (
            args.column.field === "9:30" ||
            args.column.field === "2:30" ||
            args.column.field === "4:30"
          ) {
            args.colSpan = 3;
          } else if (args.column.field === "11:00") {
            args.colSpan = 4;
          }
          break;
        case 10003:
          if (args.column.field === "9:00" || args.column.field === "11:30") {
            args.colSpan = 3;
          } else if (
            args.column.field === "10:30" ||
            args.column.field === "3:30" ||
            args.column.field === "4:30" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 2;
          }
          break;
        case 10004:
          if (args.column.field === "9:00") {
            args.colSpan = 3;
          } else if (args.column.field === "11:00") {
            args.colSpan = 4;
          } else if (
            args.column.field === "4:00" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 2;
          }
          break;
        case 10005:
          if (args.column.field === "9:00") {
            args.colSpan = 4;
          } else if (args.column.field === "11:30") {
            args.colSpan = 3;
          } else if (
            args.column.field === "3:30" ||
            args.column.field === "4:30" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 2;
          }
          break;
        case 10006:
          if (
            args.column.field === "9:00" ||
            args.column.field === "4:30" ||
            args.column.field === "2:30" ||
            args.column.field === "3:30"
          ) {
            args.colSpan = 2;
          } else if (
            args.column.field === "10:00" ||
            args.column.field === "11:30"
          ) {
            args.colSpan = 3;
          }
          break;
        case 10007:
          if (
            args.column.field === "9:00" ||
            args.column.field === "3:00" ||
            args.column.field === "10:30"
          ) {
            args.colSpan = 2;
          } else if (
            args.column.field === "11:30" ||
            args.column.field === "4:00"
          ) {
            args.colSpan = 3;
          }
          break;
        case 10008:
          if (
            args.column.field === "9:00" ||
            args.column.field === "10:30" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 3;
          } else if (args.column.field === "4:00") {
            args.colSpan = 2;
          }
          break;
        case 10009:
          if (args.column.field === "9:00" || args.column.field === "11:30") {
            args.colSpan = 3;
          } else if (
            args.column.field === "4:30" ||
            args.column.field === "2:30"
          ) {
            args.colSpan = 2;
          }
          break;
        case 100010:
          if (
            args.column.field === "9:00" ||
            args.column.field === "2:30" ||
            args.column.field === "4:00" ||
            args.column.field === "11:30"
          ) {
            args.colSpan = 3;
          } else if (args.column.field === "10:30") {
            args.colSpan = 2;
          }
          break;
      }
    },
  },
};
</script>

Limitations

Column spanning in the Vue TreeGrid has the following limitations:

  • The updateCell method does not support column spanning.
  • Column spanning is not compatible with the following features:
    1. Virtual scrolling
    2. Infinite scrolling

When using column spanning, ensure that the spanned cells do not interfere with TreeGrid operations such as sorting, filtering, or editing, as this may lead to unexpected behavior.

Column spanning via API

The column spanning feature in the Syncfusion® Vue TreeGrid allows automatically merging cells with identical values in the same row across consecutive columns. This significantly enhances readability and delivers a cleaner layout by eliminating repetitive data such as “Status”, “Permit Status”, “Inspection Status” and “Punch List Status”.

To enable column spanning, set the enableColumnSpan property to true in the Tree Grid configuration.

<template>
  <div id="app">
    <ejs-treegrid
      :dataSource="data"
      childMapping="children"
      :treeColumnIndex="0"
      :enableColumnSpan="true"
      :height="400"
      gridLines="Both"
      :enableHover="false"
      :allowSelection="false"
      :allowPaging="true"
      :pageSettings="pageSettings"
      clipMode="EllipsisWithTooltip"
    >
      <e-columns>
        <e-column
          field="activityName"
          headerText="Phase Name"
          width="250"
          freeze="Left"
        ></e-column>
        <e-column
          headerText="Schedule"
          textAlign="Center"
          :columns="scheduleColumns"
        ></e-column>
        <e-column
          headerText="Work Status"
          textAlign="Center"
          :columns="statusColumns"
        ></e-column>
        <e-column
          headerText="Compliance"
          textAlign="Center"
          :columns="complianceColumns"
        ></e-column>
        <e-column
          headerText="Personnel"
          textAlign="Center"
          :columns="personnelColumns"
        ></e-column>
        <e-column
          headerText="Materials"
          textAlign="Center"
          :columns="materialsColumns"
        ></e-column>
        <e-column
          headerText="Cost Summary"
          textAlign="Center"
          :columns="budgetColumns"
        ></e-column>
      </e-columns>
    </ejs-treegrid>
  </div>
</template>
<script setup>
import {
  TreeGridComponent as EjsTreegrid,
  ColumnDirective as EColumn,
  ColumnsDirective as EColumns,
} from "@syncfusion/ej2-vue-treegrid";
import { columnSpanData } from "./datasource.js";

const data = columnSpanData;
const pageSettings = { pageSize: 18, pageSizeMode: 'All' };
const scheduleColumns: [
        { field: 'startDate', headerText: 'Start Date', type: 'date', format: 'MM/dd/yyyy', width: 140, textAlign: 'Center' },
        { field: 'endDate', headerText: 'End Date', type: 'date', format: 'MM/dd/yyyy', width: 140, textAlign: 'Center' }
];
     const personnelColumns: [
        {
          field: 'supervisor',
          headerText: 'Supervisor',
          width: 180,
        },
        { field: 'team', headerText: 'Crew', width: 200 }
      ];
      const statusColumns: [
        { field: 'status', headerText: 'Status', width: 180, textAlign: 'Center' }
      ];
      const complianceColumns: [
        { field: 'permitStatus', headerText: 'Permit Status', width: 160, textAlign: 'Center' },
        { field: 'inspectionDate', headerText: 'Inspection Date', width: 180, type: 'date', format: 'MM/dd/yyyy', textAlign: 'Center' },
        { field: 'inspectionStatus', headerText: 'Inspection Status', width: 180, textAlign: 'Center' },
        { field: 'punchListStatus', headerText: 'Punch List Status', width: 180, textAlign: 'Center' }
      ];
      const materialsColumns: [
        { field: 'materialUsed', headerText: 'Materials Used', width: 180, textAlign: 'Center' },
        { field: 'materialCost', headerText: 'Material Cost', width: 140, format: 'C2', textAlign: 'Right', enableColumnSpan: false }
      ];
      const budgetColumns: [
        { field: 'totalBudget', headerText: 'Planned Budget', width: 140, format: 'C2', textAlign: 'Center', enableColumnSpan: false },
        { field: 'paidToDate', headerText: 'Actual Spend', width: 140, format: 'C2', textAlign: 'Center', enableColumnSpan: false }
      ];
</script>
<template>
<div id="app">
      <ejs-treegrid :dataSource="data" childMapping="children" :treeColumnIndex="0" :enableColumnSpan="true"
        :height=400 gridLines="Both" :enableHover=false :allowSelection=false :allowPaging='true'
        :pageSettings='pageSettings' clipMode='EllipsisWithTooltip'>
        <e-columns>
          <e-column field="activityName" headerText="Phase Name" width="250" freeze='Left'></e-column>
          <e-column headerText="Schedule" textAlign="Center" :columns="scheduleColumns"></e-column>
          <e-column headerText="Work Status" textAlign="Center" :columns="statusColumns"></e-column>
          <e-column headerText="Compliance" textAlign="Center" :columns="complianceColumns"></e-column>
          <e-column headerText="Personnel" textAlign="Center" :columns="personnelColumns"></e-column>
          <e-column headerText="Materials" textAlign="Center" :columns="materialsColumns"></e-column>
          <e-column headerText="Cost Summary" textAlign="Center" :columns="budgetColumns"></e-column>
        </e-columns>
      </ejs-treegrid>
</div>
</template>
<script>

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

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

},

  data() {
    return {
      data: columnSpanData,
      pageSettings: { pageSizeMode: 'All', pageSize: 18 },
      scheduleColumns: [
        { field: 'startDate', headerText: 'Start Date', type: 'date', format: 'MM/dd/yyyy', width: 140, textAlign: 'Center' },
        { field: 'endDate', headerText: 'End Date', type: 'date', format: 'MM/dd/yyyy', width: 140, textAlign: 'Center' }
      ],
      personnelColumns: [
        {
          field: 'supervisor',
          headerText: 'Supervisor',
          width: 180,
        },
        { field: 'team', headerText: 'Crew', width: 200 }
      ],
      statusColumns: [
        { field: 'status', headerText: 'Status', width: 180, textAlign: 'Center' }
      ],
      complianceColumns: [
        { field: 'permitStatus', headerText: 'Permit Status', width: 160, textAlign: 'Center' },
        { field: 'inspectionDate', headerText: 'Inspection Date', width: 180, type: 'date', format: 'MM/dd/yyyy', textAlign: 'Center' },
        { field: 'inspectionStatus', headerText: 'Inspection Status', width: 180, textAlign: 'Center' },
        { field: 'punchListStatus', headerText: 'Punch List Status', width: 180, textAlign: 'Center' }
      ],
      materialsColumns: [
        { field: 'materialUsed', headerText: 'Materials Used', width: 180, textAlign: 'Center' },
        { field: 'materialCost', headerText: 'Material Cost', width: 140, format: 'C2', textAlign: 'Right', enableColumnSpan: false }
      ],
      budgetColumns: [
        { field: 'totalBudget', headerText: 'Planned Budget', width: 140, format: 'C2', textAlign: 'Center', enableColumnSpan: false },
        { field: 'paidToDate', headerText: 'Actual Spend', width: 140, format: 'C2', textAlign: 'Center', enableColumnSpan: false }
      ]
    };
  },
  provide: {
    treegrid: [Freeze, Page]
  }
}
</script>

In the sample, column spanning is disabled at the column level for the price based columns such as “Planned Budget” and “Actual Spend” by setting each column’s enableColumnSpan property to false.

Limitations

The column spanning feature is not compatible with all functionalities available in TreeGrid and offers only limited feature support. The following list outlines the features that are not compatible with column spanning.

  • Virtualization
  • Infinite Scrolling
  • Row Drag and Drop
  • Column Virtualization
  • Detail Template
  • Editing
  • Export