diff --git a/docs/data/data-grid/column-groups/CollapsibleColumnGroups.js b/docs/data/data-grid/column-groups/CollapsibleColumnGroups.js
new file mode 100644
index 0000000000000..8d5b2e8f2c57d
--- /dev/null
+++ b/docs/data/data-grid/column-groups/CollapsibleColumnGroups.js
@@ -0,0 +1,123 @@
+import * as React from 'react';
+import { styled } from '@mui/material/styles';
+import Box from '@mui/material/Box';
+import IconButton from '@mui/material/IconButton';
+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 = {
+ 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 }) {
+ 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 (
+
+ {headerName ?? groupId}{' '}
+ {isCollapsible && (
+ {
+ const newModel = { ...columnVisibilityModel };
+ COLLAPSIBLE_COLUMN_GROUPS[groupId].forEach((field) => {
+ newModel[field] = !!isGroupCollapsed;
+ });
+ apiRef.current.setColumnVisibilityModel(newModel);
+ }}
+ >
+ {isGroupCollapsed ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+ );
+}
+
+const columnGroupingModel = [
+ {
+ groupId: 'Internal',
+ description: '',
+ children: [{ field: 'id' }],
+ },
+ {
+ groupId: 'character',
+ description: 'Information about the character',
+ headerName: 'Basic info',
+ renderHeaderGroup: (params) => {
+ return ;
+ },
+ children: [
+ {
+ groupId: 'naming',
+ headerName: 'Names',
+ renderHeaderGroup: (params) => ,
+ children: [{ field: 'lastName' }, { field: 'firstName' }],
+ },
+ { field: 'age' },
+ ],
+ },
+];
+
+const columns = [
+ { field: 'id', headerName: 'ID', width: 150 },
+ { field: 'firstName', headerName: 'First name', width: 150 },
+ { field: 'lastName', headerName: 'Last name', width: 150 },
+ { 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 (
+
+
+
+ );
+}
diff --git a/docs/data/data-grid/column-groups/CollapsibleColumnGroups.tsx b/docs/data/data-grid/column-groups/CollapsibleColumnGroups.tsx
new file mode 100644
index 0000000000000..34d5659fd2daf
--- /dev/null
+++ b/docs/data/data-grid/column-groups/CollapsibleColumnGroups.tsx
@@ -0,0 +1,129 @@
+import * as React from 'react';
+import { styled } from '@mui/material/styles';
+import Box from '@mui/material/Box';
+import IconButton from '@mui/material/IconButton';
+import {
+ DataGrid,
+ GridColDef,
+ GridColumnGroupHeaderParams,
+ GridColumnGroupingModel,
+ 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> = {
+ 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 (
+
+ {headerName ?? groupId}{' '}
+ {isCollapsible && (
+ {
+ const newModel = { ...columnVisibilityModel };
+ COLLAPSIBLE_COLUMN_GROUPS[groupId].forEach((field) => {
+ newModel[field] = !!isGroupCollapsed;
+ });
+ apiRef.current.setColumnVisibilityModel(newModel);
+ }}
+ >
+ {isGroupCollapsed ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+ );
+}
+
+const columnGroupingModel: GridColumnGroupingModel = [
+ {
+ groupId: 'Internal',
+ description: '',
+ children: [{ field: 'id' }],
+ },
+ {
+ groupId: 'character',
+ description: 'Information about the character',
+ headerName: 'Basic info',
+ renderHeaderGroup: (params) => {
+ return ;
+ },
+ children: [
+ {
+ groupId: 'naming',
+ headerName: 'Names',
+ renderHeaderGroup: (params) => ,
+ children: [{ field: 'lastName' }, { field: 'firstName' }],
+ },
+ { field: 'age' },
+ ],
+ },
+];
+
+const columns: GridColDef[] = [
+ { field: 'id', headerName: 'ID', width: 150 },
+ { field: 'firstName', headerName: 'First name', width: 150 },
+ { field: 'lastName', headerName: 'Last name', width: 150 },
+ { 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 (
+
+
+
+ );
+}
diff --git a/docs/data/data-grid/column-groups/CollapsibleColumnGroups.tsx.preview b/docs/data/data-grid/column-groups/CollapsibleColumnGroups.tsx.preview
new file mode 100644
index 0000000000000..296f04ced305f
--- /dev/null
+++ b/docs/data/data-grid/column-groups/CollapsibleColumnGroups.tsx.preview
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md
index 92df9c0b5e100..35f2c3cdb12cf 100644
--- a/docs/data/data-grid/column-groups/column-groups.md
+++ b/docs/data/data-grid/column-groups/column-groups.md
@@ -74,6 +74,12 @@ In the example below, the `Full name` column group can be divided, but not other
{{"demo": "BreakingGroupDemo.js", "disableAd": true, "bg": "inline"}}
+## Collapsible column groups
+
+The demo below uses [`renderHeaderGroup`](/x/react-data-grid/column-groups/#customize-column-group) to add a button to collapse/expand the column group.
+
+{{"demo": "CollapsibleColumnGroups.js", "bg": "inline"}}
+
## Manage group visibility 🚧
The column group should allow to switch between an extended/collapsed view which hide/show some columns.