Data Grid - Column groups
Group your columns.
Grouping columns lets you have a multi-level hierarchy of columns in your header.
Define column groups
You can define column groups with the columnGroupingModel prop.
This prop receives an array of column groups.
A column group is defined by at least two properties:
groupId: a string used to identify the groupchildren: an array containing the children of the group
The children attribute can contain two types of objects:
- leaves with type
{ field: string }, which add the column with the correspondingfieldto this group - other column groups, making it possible to create nested groups
<DataGrid
columnGroupingModel={[
{
groupId: 'internal data',
children: [{ field: 'id' }],
},
{
groupId: 'character',
children: [
{
groupId: 'naming',
children: [{ field: 'lastName' }, { field: 'firstName' }],
},
{ field: 'age' },
],
},
]}
/>
import type { GridColDef, GridColumnGroupingModel } from '@mui/x-data-grid';
import { DataGrid } from '@mui/x-data-grid';
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', width: 90 },
{
field: 'firstName',
headerName: 'First name',
rowHeader: true,
width: 150,
},
{
field: 'lastName',
headerName: 'Last name',
rowHeader: true,
width: 150,
},
{
field: 'age',
headerName: 'Age',
type: 'number',
width: 110,
},
];
const rows = [
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 14 },
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 31 },
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 31 },
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 11 },
{ id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null },
{ id: 6, lastName: 'Melisandre', firstName: null, age: 150 },
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
];
const columnGroupingModel: GridColumnGroupingModel = [
{
groupId: 'Internal',
description: '',
children: [{ field: 'id' }],
},
{
groupId: 'Basic info',
children: [
{
groupId: 'Full name',
children: [{ field: 'lastName' }, { field: 'firstName' }],
},
{ field: 'age' },
],
},
];
export default function BasicGroupingDemo() {
return (
<div style={{ height: 400, width: '100%' }}>
<DataGrid
rows={rows}
columns={columns}
checkboxSelection
disableRowSelectionOnClick
columnGroupingModel={columnGroupingModel}
/>
</div>
);
}
Customize column group
In addition to the required groupId and children, you can use the following optional properties to customize a column group:
headerName: the string displayed as the column's name (instead ofgroupId).description: a text for the tooltip.headerClassName: a CSS class for styling customization.renderHeaderGroup: a function returning custom React component.
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import type {
GridColDef,
GridColumnGroupHeaderParams,
GridColumnGroupingModel,
} from '@mui/x-data-grid';
import { DataGrid } from '@mui/x-data-grid';
import BuildIcon from '@mui/icons-material/Build';
import PersonIcon from '@mui/icons-material/Person';
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', width: 150 },
{
field: 'firstName',
headerName: 'First name',
rowHeader: true,
width: 150,
},
{
field: 'lastName',
headerName: 'Last name',
rowHeader: true,
width: 150,
},
{
field: 'age',
headerName: 'Age',
type: 'number',
width: 110,
},
];
const rows = [
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 14 },
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 31 },
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 31 },
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 11 },
{ id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null },
{ id: 6, lastName: 'Melisandre', firstName: null, age: 150 },
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
];
interface HeaderWithIconProps extends GridColumnGroupHeaderParams {
icon: React.ReactNode;
}
const HeaderWithIconRoot = styled('div')(({ theme }) => ({
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
'& span': {
overflow: 'hidden',
textOverflow: 'ellipsis',
marginRight: theme.spacing(0.5),
},
}));
function HeaderWithIcon(props: HeaderWithIconProps) {
const { icon, ...params } = props;
return (
<HeaderWithIconRoot>
<span>{params.headerName ?? params.groupId}</span> {icon}
</HeaderWithIconRoot>
);
}
const columnGroupingModel: GridColumnGroupingModel = [
{
groupId: 'internal_data',
headerName: 'Internal',
description: '',
renderHeaderGroup: (params) => (
<HeaderWithIcon {...params} icon={<BuildIcon fontSize="small" />} />
),
children: [{ field: 'id' }],
},
{
groupId: 'character',
description: 'Information about the character',
headerName: 'Basic info',
renderHeaderGroup: (params) => (
<HeaderWithIcon {...params} icon={<PersonIcon fontSize="small" />} />
),
children: [
{
groupId: 'naming',
headerName: 'Names',
headerClassName: 'my-super-theme--naming-group',
children: [{ field: 'lastName' }, { field: 'firstName' }],
},
{ field: 'age' },
],
},
];
export default function CustomizationDemo() {
return (
<Box
sx={{
height: 400,
width: '100%',
'& .my-super-theme--naming-group': {
backgroundColor: 'rgba(255, 7, 0, 0.55)',
},
}}
>
<DataGrid
rows={rows}
columns={columns}
checkboxSelection
disableRowSelectionOnClick
columnGroupingModel={columnGroupingModel}
/>
</Box>
);
}
Group header height
By default, column group headers are the same height as column headers. This will be the default 56 pixels or a custom value set with the columnHeaderHeight prop.
The columnGroupHeaderHeight prop can be used to size column group headers independently of column headers.
import type { GridColDef, GridColumnGroupingModel } from '@mui/x-data-grid';
import { DataGrid } from '@mui/x-data-grid';
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', width: 90 },
{
field: 'firstName',
headerName: 'First name',
rowHeader: true,
width: 150,
},
{
field: 'lastName',
headerName: 'Last name',
rowHeader: true,
width: 150,
},
{
field: 'age',
headerName: 'Age',
type: 'number',
width: 110,
},
];
const rows = [
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 14 },
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 31 },
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 31 },
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 11 },
{ id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null },
{ id: 6, lastName: 'Melisandre', firstName: null, age: 150 },
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
];
const columnGroupingModel: GridColumnGroupingModel = [
{
groupId: 'Internal',
description: '',
children: [{ field: 'id' }],
},
{
groupId: 'Basic info',
children: [
{
groupId: 'Full name',
children: [{ field: 'lastName' }, { field: 'firstName' }],
},
{ field: 'age' },
],
},
];
export default function GroupHeaderHeight() {
return (
<div style={{ height: 400, width: '100%' }}>
<DataGrid
rows={rows}
columns={columns}
columnGroupingModel={columnGroupingModel}
columnGroupHeaderHeight={36}
/>
</div>
);
}
Column reordering
By default, the columns that are part of a group cannot be dragged to outside their group.
You can customize this behavior on specific groups by setting freeReordering: true in a column group object.
In the example below, the Full name column group can be divided, but not other column groups.
import type { GridColDef, GridColumnGroupingModel } from '@mui/x-data-grid-pro';
import { DataGridPro } from '@mui/x-data-grid-pro';
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', width: 100 },
{ field: 'isAdmin', type: 'boolean', headerName: 'is admin', width: 100 },
{
field: 'firstName',
headerName: 'First name',
rowHeader: true,
width: 150,
},
{
field: 'lastName',
headerName: 'Last name',
rowHeader: true,
width: 150,
},
{
field: 'age',
headerName: 'Age',
type: 'number',
width: 110,
},
];
const rows = [
{ id: 1, isAdmin: false, lastName: 'Snow', firstName: 'Jon', age: 14 },
{ id: 2, isAdmin: true, lastName: 'Lannister', firstName: 'Cersei', age: 31 },
{ id: 3, isAdmin: false, lastName: 'Lannister', firstName: 'Jaime', age: 31 },
{ id: 4, isAdmin: false, lastName: 'Stark', firstName: 'Arya', age: 11 },
{ id: 5, isAdmin: true, lastName: 'Targaryen', firstName: 'Daenerys', age: null },
{ id: 6, isAdmin: true, lastName: 'Melisandre', firstName: null, age: 150 },
{ id: 7, isAdmin: false, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
{ id: 8, isAdmin: false, lastName: 'Frances', firstName: 'Rossini', age: 36 },
{ id: 9, isAdmin: false, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
];
const columnGroupingModel: GridColumnGroupingModel = [
{
groupId: 'internal_data',
headerName: 'Internal (not freeReordering)',
description: '',
children: [{ field: 'id' }, { field: 'isAdmin' }],
},
{
groupId: 'naming',
headerName: 'Full name (freeReordering)',
freeReordering: true,
children: [{ field: 'lastName' }, { field: 'firstName' }],
},
];
export default function BreakingGroupDemo() {
return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPro
rows={rows}
columns={columns}
checkboxSelection
disableRowSelectionOnClick
columnGroupingModel={columnGroupingModel}
/>
</div>
);
}
Collapsible column groups
The demo below uses renderHeaderGroup to add a button to collapse/expand the column group.
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
import type {
GridColDef,
GridColumnGroupHeaderParams,
GridColumnGroupingModel,
} from '@mui/x-data-grid';
import {
DataGrid,
gridColumnVisibilityModelSelector,
useGridApiContext,
} from '@mui/x-data-grid';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
const COLLAPSIBLE_COLUMN_GROUPS: Record<string, Array<string>> = {
character: ['lastName', 'age'],
naming: ['lastName'],
};
const ColumnGroupRoot = styled('div')({
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
});
const ColumnGroupTitle = styled('span')({
overflow: 'hidden',
textOverflow: 'ellipsis',
});
function CollapsibleHeaderGroup({
groupId,
headerName,
}: GridColumnGroupHeaderParams) {
const apiRef = useGridApiContext();
const columnVisibilityModel = gridColumnVisibilityModelSelector(apiRef);
if (!groupId) {
return null;
}
const isCollapsible = Boolean(COLLAPSIBLE_COLUMN_GROUPS[groupId]);
const isGroupCollapsed = COLLAPSIBLE_COLUMN_GROUPS[groupId].every(
(field) => columnVisibilityModel[field] === false,
);
return (
<ColumnGroupRoot>
<ColumnGroupTitle>{headerName ?? groupId}</ColumnGroupTitle>{' '}
{isCollapsible && (
<IconButton
sx={{ ml: 0.5 }}
onClick={() => {
const newModel = { ...columnVisibilityModel };
COLLAPSIBLE_COLUMN_GROUPS[groupId].forEach((field) => {
newModel[field] = !!isGroupCollapsed;
});
apiRef.current.setColumnVisibilityModel(newModel);
}}
>
{isGroupCollapsed ? (
<KeyboardArrowRightIcon fontSize="small" />
) : (
<KeyboardArrowDownIcon fontSize="small" />
)}
</IconButton>
)}
</ColumnGroupRoot>
);
}
const columnGroupingModel: GridColumnGroupingModel = [
{
groupId: 'Internal',
description: '',
children: [{ field: 'id' }],
},
{
groupId: 'character',
description: 'Information about the character',
headerName: 'Basic info',
renderHeaderGroup: (params) => {
return <CollapsibleHeaderGroup {...params} />;
},
children: [
{
groupId: 'naming',
headerName: 'Names',
renderHeaderGroup: (params) => <CollapsibleHeaderGroup {...params} />,
children: [{ field: 'lastName' }, { field: 'firstName' }],
},
{ field: 'age' },
],
},
];
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', width: 150 },
{ field: 'firstName', headerName: 'First name', width: 150, rowHeader: true },
{ field: 'lastName', headerName: 'Last name', width: 150, rowHeader: true },
{ field: 'age', headerName: 'Age', type: 'number', width: 110 },
];
const rows = [
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 },
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 },
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 },
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 },
{ id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null },
{ id: 6, lastName: 'Melisandre', firstName: null, age: 150 },
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
];
export default function CollapsibleColumnGroups() {
return (
<Box sx={{ height: 400, width: '100%' }}>
<DataGrid
rows={rows}
columns={columns}
checkboxSelection
disableRowSelectionOnClick
columnGroupingModel={columnGroupingModel}
/>
</Box>
);
}
Manage group visibility 🚧
With this feature, users would be able to expand and collapse grouped columns to toggle their visibility.
Column group ordering 🚧
With this feature, users would be able to drag and drop grouped headers to move all grouped children at once (which is already possible for normal columns).