Row spanning in EJ2 JavaScript Grid control

21 Aug 202524 minutes to read

The grid provides an option to span row cells, allowing you to merge two or more cells in a row into a single cell. This feature can be useful in scenarios where you want to display information that spans across multiple rows, but want to avoid repeating the same information in each row.

To achieve this, You need to define the rowSpan attribute to span cells in the queryCellInfo event. The rowSpan attribute is used to specify the number of rows that the current cell should span.

The queryCellInfo event is triggered for each cell in the grid, and allows you to customize the cells in the grid. By handling this event, you can set the rowSpan attribute for a cell to achieve row spanning.

In the following demo, Davolio cell is spanned to two rows in the EmployeeName column.Also Grid supports the spanning of rows and columns for same cells. Lunch Break cell is spanned to two rows and three columns in the 1:00 column.

var grid = new ej.grids.Grid({
    dataSource: columnSpanData,
    queryCellInfo: QueryCellEvent,
    gridLines: 'Both',
    columns: [
        { field: 'EmployeeID', headerText: 'Employee ID', isPrimaryKey: true, textAlign: 'Right', width: 150 },
        { field: 'EmployeeName', headerText: 'Employee Name', width: 200 },
        { field: '9:00', headerText: '9.00 AM', width: 120 },
        { field: '9:30', headerText: '9.30 AM', width: 120 },
        { field: '10:00', headerText: '10.00 AM', width: 120 },
        { field: '10:30', headerText: '10.30 AM', width: 120 },
        { field: '11:00', headerText: '11.00 AM', width: 120 },
        { field: '11:30', headerText: '11.30 AM', width: 120 },
        { field: '12:00', headerText: '12.00 PM', width: 120 },
        { field: '12:30', headerText: '12.30 PM', width: 120 },
        { field: '1:00', headerText: '1.00 PM', width: 120 },
        { field: '1:30', headerText: '1.30 PM', width: 120 },
        { field: '2:00', headerText: '2.00 PM', width: 120 },
        { field: '2:30', headerText: '2.30 PM', width: 120 },
        { field: '3:00', headerText: '3.00 PM', width: 120 },
        { field: '3:30', headerText: '3.30 PM', width: 120 },
        { field: '4:00', headerText: '4.00 PM', width: 120 },
        { field: '4:30', headerText: '4.30 PM', width: 120 },
        { field: '5:00', headerText: '5.00 PM', width: 120 }
    ],
    width: 'auto',
    height: 300,
    allowTextWrap: true
});
grid.appendTo('#Grid');

function QueryCellEvent(args) {
    var 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;
            } else if (args.column.field === 'EmployeeName') {
                args.rowSpan = 2;
            } else if (args.column.field === '1:00') {
                args.colSpan = 3;
                args.rowSpan = 2;
            }
            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;
    }
}
<!DOCTYPE html><html lang="en">
<head>
    <title>EJ2 Grid</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Grid Control">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-base/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-buttons/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-popups/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-navigations/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-lists/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-inputs/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-calendars/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-grids/styles/bootstrap5.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/31.1.17/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
<body> 
    <div id="container">
        <div id="Grid"></div>        
    </div>
<script>
var ele = document.getElementById('container');
if(ele) {
  ele.style.visibility = "visible";
}   
</script>
<script src="index.js" type="text/javascript"></script>
</body></html>

To disable the spanning for particular grid page, you need to use requestType from queryCellInfo event argument.
The rowSpan and colSpan attributes can be used together to merge cells both vertically and horizontally.

Limitations

  • The updateCell method does not support row spanning.
  • Row spanning is not compatible with the following features:
    1. Virtual scrolling
    2. Infinite scrolling
    3. Grouping
    4. Row drag and drop
    5. Autofill
    6. Inline editing
    7. Batch editing
    8. CRUD

Row spanning using enableRowSpan property

The Syncfusion EJ2 JavaScript Grid introduces a simplified approach to vertically merge cells using the enableRowSpan property.

When the enableRowSpan property is enabled, the Grid automatically merges cells with matching data across adjacent columns without requiring manual span configuration using the queryCellInfo event. These merged cells are visually combined into a single cell, improving readability.

Here is an example of how to use the enableRowSpan property to merge cells vertically:

var grid = new ej.grids.Grid({
    dataSource: telecastData,
    gridLines: 'Both',
    enableHover: false,
    allowSelection: false,
    allowSorting: true,
    enableRowSpan: true,
    columns: [
        { field: 'Channel', headerText: 'Channel', width: 150, freeze: 'Left', isPrimaryKey: true },
        { field: 'Genre', headerText: 'Genre', width: 120, freeze: 'Left' },
        { field: 'Program12AM', headerText: '12 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program1AM', headerText: '1 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program2AM', headerText: '2 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program3AM', headerText: '3 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program4AM', headerText: '4 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program5AM', headerText: '5 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program6AM', headerText: '6 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program7AM', headerText: '7 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program8AM', headerText: '8 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program9AM', headerText: '9 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program10AM', headerText: '10 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program11AM', headerText: '11 AM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program12PM', headerText: '12 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program1PM', headerText: '1 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program2PM', headerText: '2 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program3PM', headerText: '3 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program4PM', headerText: '4 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program5PM', headerText: '5 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program6PM', headerText: '6 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program7PM', headerText: '7 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program8PM', headerText: '8 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program9PM', headerText: '9 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program10PM', headerText: '10 PM', width: 110, textAlign: 'Center', allowSorting: false},
        { field: 'Program11PM', headerText: '11 PM', width: 110, textAlign: 'Center', allowSorting: false},
    ],
    width: 'auto',
    height: 450,
    allowTextWrap: true,
    textWrapSettings: { wrapMode: 'Content' },
});
grid.appendTo('#Grid');
<!DOCTYPE html><html lang="en">
<head>
    <title>EJ2 Grid</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Typescript Grid Control">
    <meta name="author" content="Syncfusion">
    <link href="index.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-base/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-buttons/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-popups/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-navigations/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-dropdowns/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-lists/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-inputs/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-calendars/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-splitbuttons/styles/bootstrap5.css" rel="stylesheet">
    <link href="https://cdn.syncfusion.com/ej2/31.1.17/ej2-grids/styles/bootstrap5.css" rel="stylesheet">
<script src="https://cdn.syncfusion.com/ej2/31.1.17/dist/ej2.min.js" type="text/javascript"></script>
<script src="es5-datasource.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
<body> 
    <div id="container">
        <div id="Grid"></div>        
    </div>
<script>
var ele = document.getElementById('container');
if(ele) {
  ele.style.visibility = "visible";
}   
</script>
<script src="index.js" type="text/javascript"></script>
</body></html>

You can also control spanning at the column level. To prevent merging for specific columns, set enableRowSpan to false in the column definition.

Limitation

  • Virtualization
  • Infinite Scrolling
  • Lazy Load Grouping
  • Row Drag and Drop
  • Column Virtualization
  • Detail Template
  • Editing
  • Export
  • Foreign Key
  • Hierarchy Grid