Column spanning in React TreeGrid
The column spanning feature in the Syncfusion® React 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.
import { ColumnDirective, ColumnsDirective, TreeGridComponent } from '@syncfusion/ej2-react-treegrid';
import * as React from 'react';
import { columnSpanData } from './datasource';
function App() {
const queryCellInfoEvent = (args) => {
const col = args.column;
const data = args.data;
switch (data.EmployeeID) {
case 10001:
if (col.field === '9:00' || col.field === '2:30' || col.field === '4:30') {
args.colSpan = 2;
}
else if (col.field === '11:00') {
args.colSpan = 3;
}
break;
case 10002:
if (col.field === '9:30' || col.field === '2:30' ||
col.field === '4:30') {
args.colSpan = 3;
}
else if (col.field === '11:00') {
args.colSpan = 4;
}
break;
case 10003:
if (col.field === '9:00' || col.field === '11:30') {
args.colSpan = 3;
}
else if (col.field === '10:30' || col.field === '3:30' ||
col.field === '4:30' || col.field === '2:30') {
args.colSpan = 2;
}
break;
case 10004:
if (col.field === '9:00') {
args.colSpan = 3;
}
else if (col.field === '11:00') {
args.colSpan = 4;
}
else if (col.field === '4:00' || col.field === '2:30') {
args.colSpan = 2;
}
break;
case 10005:
if (col.field === '9:00') {
args.colSpan = 4;
}
else if (col.field === '11:30') {
args.colSpan = 3;
}
else if (col.field === '3:30' || col.field === '4:30' || col.field === '2:30') {
args.colSpan = 2;
}
break;
case 10006:
if (col.field === '9:00' || col.field === '4:30' ||
col.field === '2:30' || col.field === '3:30') {
args.colSpan = 2;
}
else if (col.field === '10:00' || col.field === '11:30') {
args.colSpan = 3;
}
break;
case 10007:
if (col.field === '9:00' || col.field === '3:00' || col.field === '10:30') {
args.colSpan = 2;
}
else if (col.field === '11:30' || col.field === '4:00') {
args.colSpan = 3;
}
break;
case 10008:
if (col.field === '9:00' || col.field === '10:30' || col.field === '2:30') {
args.colSpan = 3;
}
else if (col.field === '4:00') {
args.colSpan = 2;
}
break;
case 10009:
if (col.field === '9:00' || col.field === '11:30') {
args.colSpan = 3;
}
else if (col.field === '4:30' || col.field === '2:30') {
args.colSpan = 2;
}
break;
case 100010:
if (col.field === '9:00' || col.field === '2:30' ||
col.field === '4:00' || col.field === '11:30') {
args.colSpan = 3;
}
else if (col.field === '10:30') {
args.colSpan = 2;
}
break;
}
};
return (<div className='control-pane'>
<div className='control-section'>
<TreeGridComponent dataSource={columnSpanData} queryCellInfo={queryCellInfoEvent} treeColumnIndex={1} childMapping='subtasks' height='auto' width='auto' gridLines='Both'>
<ColumnsDirective>
<ColumnDirective field='EmployeeID' headerText='Employee ID' width='150' textAlign='Right'/>
<ColumnDirective field='EmployeeName' headerText='Employee Name' width='200'/>
<ColumnDirective field='9:00' headerText='9:00 AM' width='120'/>
<ColumnDirective field='9:30' headerText='9:30 AM' width='120'/>
<ColumnDirective field='10:00' headerText='10:00 AM' width='120'/>
<ColumnDirective field='10:30' headerText='10:30 AM' width='120'/>
<ColumnDirective field='11:00' headerText='11:00 AM' width='120'/>
<ColumnDirective field='11:30' headerText='11:30 AM' width='120'/>
<ColumnDirective field='12:00' headerText='12:00 PM' width='120'/>
<ColumnDirective field='12:30' headerText='12:30 PM' width='120'/>
<ColumnDirective field='2:30' headerText='2:30 PM' width='120'/>
<ColumnDirective field='3:00' headerText='3:00 PM' width='120'/>
<ColumnDirective field='3:30' headerText='3:30 PM' width='120'/>
<ColumnDirective field='4:00' headerText='4:00 PM' width='120'/>
<ColumnDirective field='4:30' headerText='4:30 PM' width='120'/>
<ColumnDirective field='5:00' headerText='5:00 PM' width='120'/>
</ColumnsDirective>
</TreeGridComponent>
</div>
</div>);
}
;
export default App;import { Column, ColumnDirective, ColumnsDirective, TreeGridComponent } from '@syncfusion/ej2-react-treegrid';
import { QueryCellInfoEventArgs } from '@syncfusion/ej2-react-grids';
import * as React from 'react';
import { columnSpanData } from './datasource';
function App() {
const queryCellInfoEvent = (args: QueryCellInfoEventArgs) => {
const col: Column = args.column as Column;
const data = args.data;
switch (data.EmployeeID) {
case 10001:
if (col.field === '9:00' || col.field === '2:30' || col.field === '4:30') {
args.colSpan = 2;
} else if (col.field === '11:00') {
args.colSpan = 3;
}
break;
case 10002:
if (col.field === '9:30' || col.field === '2:30' ||
col.field === '4:30') {
args.colSpan = 3;
} else if (col.field === '11:00') {
args.colSpan = 4;
}
break;
case 10003:
if (col.field === '9:00' || col.field === '11:30') {
args.colSpan = 3;
} else if (col.field === '10:30' || col.field === '3:30' ||
col.field === '4:30' || col.field === '2:30') {
args.colSpan = 2;
}
break;
case 10004:
if (col.field === '9:00') {
args.colSpan = 3;
} else if (col.field === '11:00') {
args.colSpan = 4;
} else if (col.field === '4:00' || col.field === '2:30') {
args.colSpan = 2;
}
break;
case 10005:
if (col.field === '9:00') {
args.colSpan = 4;
} else if (col.field === '11:30') {
args.colSpan = 3;
} else if (col.field === '3:30' || col.field === '4:30' || col.field === '2:30') {
args.colSpan = 2;
}
break;
case 10006:
if (col.field === '9:00' || col.field === '4:30' ||
col.field === '2:30' || col.field === '3:30') {
args.colSpan = 2;
} else if (col.field === '10:00' || col.field === '11:30') {
args.colSpan = 3;
}
break;
case 10007:
if (col.field === '9:00' || col.field === '3:00' || col.field === '10:30') {
args.colSpan = 2;
} else if (col.field === '11:30' || col.field === '4:00') {
args.colSpan = 3;
}
break;
case 10008:
if (col.field === '9:00' || col.field === '10:30' || col.field === '2:30') {
args.colSpan = 3;
} else if (col.field === '4:00') {
args.colSpan = 2;
}
break;
case 10009:
if (col.field === '9:00' || col.field === '11:30') {
args.colSpan = 3;
} else if (col.field === '4:30' || col.field === '2:30') {
args.colSpan = 2;
}
break;
case 100010:
if (col.field === '9:00' || col.field === '2:30' ||
col.field === '4:00' || col.field === '11:30') {
args.colSpan = 3;
} else if (col.field === '10:30') {
args.colSpan = 2;
}
break;
}
};
return (<div className='control-pane'>
<div className='control-section'>
<TreeGridComponent dataSource={columnSpanData} queryCellInfo={queryCellInfoEvent} treeColumnIndex={1} childMapping='subtasks' height='auto' width='auto' gridLines='Both' >
<ColumnsDirective>
<ColumnDirective field='EmployeeID' headerText='Employee ID' width='150' textAlign='Right' />
<ColumnDirective field='EmployeeName' headerText='Employee Name' width='200' />
<ColumnDirective field='9:00' headerText='9:00 AM' width='120' />
<ColumnDirective field='9:30' headerText='9:30 AM' width='120' />
<ColumnDirective field='10:00' headerText='10:00 AM' width='120' />
<ColumnDirective field='10:30' headerText='10:30 AM' width='120' />
<ColumnDirective field='11:00' headerText='11:00 AM' width='120' />
<ColumnDirective field='11:30' headerText='11:30 AM' width='120' />
<ColumnDirective field='12:00' headerText='12:00 PM' width='120' />
<ColumnDirective field='12:30' headerText='12:30 PM' width='120' />
<ColumnDirective field='2:30' headerText='2:30 PM' width='120' />
<ColumnDirective field='3:00' headerText='3:00 PM' width='120' />
<ColumnDirective field='3:30' headerText='3:30 PM' width='120' />
<ColumnDirective field='4:00' headerText='4:00 PM' width='120' />
<ColumnDirective field='4:30' headerText='4:30 PM' width='120' />
<ColumnDirective field='5:00' headerText='5:00 PM' width='120' />
</ColumnsDirective>
</TreeGridComponent>
</div>
</div>)
};
export default App;Limitations
Column spanning in the React TreeGrid has the following limitations:
- The updateCell method does not support column spanning.
- Column spanning is not compatible with the following features:
- Virtual scrolling
- 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 implementation through API
The Syncfusion React TreeGrid provides an API-based approach to horizontally merge cells with identical values in the same row across adjacent columns.
The column spanning feature in the Syncfusion React TreeGrid can be enabled using enableColumnSpan property to true in the TreeGrid configuration, which significantly enhances readability and delivers a cleaner layout by eliminating repetitive data in columns such as “Status”, “Permit Status”, “Inspection Status” and “Punch List Status”.
import * as React from "react";
import { createRoot } from "react-dom/client";
import {
ColumnDirective,
ColumnsDirective,
TreeGridComponent,
Inject,
Page,
Freeze,
} from "@syncfusion/ej2-react-treegrid";
import { columnSpanData } from "./datasource";
function App() {
return (
<div className="control-pane">
<div className="control-section">
<TreeGridComponent
dataSource={columnSpanData}
enableHover={false}
allowSelection={false}
allowPaging={true}
pageSettings=
rowHeight={50}
gridLines="Both"
enableColumnSpan={true}
height={315}
childMapping="children"
treeColumnIndex={0}
clipMode="EllipsisWithTooltip"
>
<ColumnsDirective>
<ColumnDirective
field="activityName"
headerText="Phase Name"
width="250"
freeze="Left"
/>
<ColumnDirective
headerText="Schedule"
textAlign="Center"
columns={[
{
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",
},
]}
/>
<ColumnDirective
headerText="Work Status"
textAlign="Center"
columns={[
{
field: "status",
headerText: "Status",
width: 180,
textAlign: "Center",
},
]}
/>
<ColumnDirective
headerText="Compliance"
textAlign="Center"
columns={[
{
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",
},
]}
/>
<ColumnDirective
headerText="Personnel"
textAlign="Center"
columns={[
{ field: "supervisor", headerText: "Supervisor", width: 180 },
{ field: "team", headerText: "Crew", width: 200 },
]}
/>
<ColumnDirective
headerText="Materials"
textAlign="Center"
columns={[
{
field: "materialUsed",
headerText: "Materials Used",
width: 180,
textAlign: "Center",
},
{
field: "materialCost",
headerText: "Material Cost",
width: 140,
format: "C2",
textAlign: "Right",
enableColumnSpan: false,
},
]}
/>
<ColumnDirective
headerText="Cost Summary"
textAlign="Center"
columns={[
{
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,
},
]}
/>
</ColumnsDirective>
<Inject services={[Freeze, Page]} />
</TreeGridComponent>
</div>
</div>
);
}
export default App;import * as React from 'react';
import { createRoot } from 'react-dom/client';
import {
ColumnDirective,
ColumnsDirective,
TreeGridComponent,
Inject,
Page,
Freeze,
} from "@syncfusion/ej2-react-treegrid";
import { columnSpanData } from "./datasource";
function App() {
return (<div className='control-pane'>
<div className='control-section'>
<TreeGridComponent
dataSource={columnSpanData}
enableHover={false}
allowSelection={false}
allowPaging={true}
pageSettings=
rowHeight={50}
gridLines="Both"
enableColumnSpan={true}
height={315}
childMapping="children"
treeColumnIndex={0}
clipMode="EllipsisWithTooltip"
>
<ColumnsDirective>
<ColumnDirective
field="activityName"
headerText="Phase Name"
width="250"
freeze="Left"
></ColumnDirective>
<ColumnDirective
headerText="Schedule"
textAlign="Center"
columns={[
{
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",
},
]}
></ColumnDirective>
<ColumnDirective
headerText="Work Status"
textAlign="Center"
columns={[
{
field: "status",
headerText: "Status",
width: 180,
textAlign: "Center",
},
]}
></ColumnDirective>
<ColumnDirective
headerText="Compliance"
textAlign="Center"
columns={[
{
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",
},
]}
></ColumnDirective>
<ColumnDirective
headerText="Personnel"
textAlign="Center"
columns={[
{ field: "supervisor", headerText: "Supervisor", width: 180 },
{ field: "team", headerText: "Crew", width: 200 },
]}
></ColumnDirective>
<ColumnDirective
headerText="Materials"
textAlign="Center"
columns={[
{
field: "materialUsed",
headerText: "Materials Used",
width: 180,
textAlign: "Center",
},
{
field: "materialCost",
headerText: "Material Cost",
width: 140,
format: "C2",
textAlign: "Right",
enableColumnSpan: false,
},
]}
></ColumnDirective>
<ColumnDirective
headerText="Cost Summary"
textAlign="Center"
columns={[
{
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,
},
]}
></ColumnDirective>
</ColumnsDirective>
<Inject services={[Freeze, Page]} />
</TreeGridComponent>
</div>
</div>
);
};
export default App;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
enableColumnSpanproperty to false.
Limitations
Column spanning feature is not compatible with all the features which are available in TreeGrid and it has limited features support. Here we have listed out the features which are not compatible with column spanning feature.
- Virtualization
- Infinite Scrolling
- Row Drag and Drop
- Column Virtualization
- Detail Template
- Editing
- Export