+ );
+}
diff --git a/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx.preview b/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx.preview
new file mode 100644
index 0000000000000..6f326f7a9cd17
--- /dev/null
+++ b/docs/data/data-grid/column-definition/ActionsWithModalGrid.tsx.preview
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/data/data-grid/column-definition/column-definition.md b/docs/data/data-grid/column-definition/column-definition.md
index 1c66b0e72c4ff..48e6c1b465cd2 100644
--- a/docs/data/data-grid/column-definition/column-definition.md
+++ b/docs/data/data-grid/column-definition/column-definition.md
@@ -231,6 +231,8 @@ The following are the native column types with their required value types:
| `'singleSelect'` | A value in `.valueOptions` |
| `'actions'` | Not applicable |
+{{"demo": "ColumnTypesGrid.js", "bg": "inline"}}
+
### Converting types
Default methods, such as filtering and sorting, assume that the type of the values will match the type of the column specified in `type`.
@@ -250,57 +252,67 @@ If for any reason, your data type is not the correct one, you can use `valueGett
To use most of the column types, you only need to define the `type` property in your column definition.
However, some types require additional properties to be set to make them work correctly:
-- If the column type is `'singleSelect'`, you also need to set the `valueOptions` property in the respective column definition. These values are options used for filtering and editing.
+#### Single select
- ```tsx
- {
- field: 'country',
- type: 'singleSelect',
- valueOptions: ['United Kingdom', 'Spain', 'Brazil']
- }
- ```
-
- :::warning
- When using objects values for `valueOptions` you need to provide the `value` and `label` attributes for each option.
- However, you can customize which attribute is used as value and label by using `getOptionValue` and `getOptionLabel`, respectively.
-
- ```tsx
- // Without getOptionValue and getOptionLabel
- {
- valueOptions: [
- { value: 'BR', label: 'Brazil' },
- { value: 'FR', label: 'France' }
- ]
- }
+If the column type is `'singleSelect'`, you also need to set the `valueOptions` property in the respective column definition. These values are options used for filtering and editing.
- // With getOptionValue and getOptionLabel
- {
- getOptionValue: (value: any) => value.code,
- getOptionLabel: (value: any) => value.name,
- valueOptions: [
- { code: 'BR', name: 'Brazil' },
- { code: 'FR', name: 'France' }
- ]
- }
- ```
+```tsx
+{
+ field: 'country',
+ type: 'singleSelect',
+ valueOptions: ['United Kingdom', 'Spain', 'Brazil']
+}
+```
- :::
+:::warning
+When using objects values for `valueOptions` you need to provide the `value` and `label` attributes for each option.
+However, you can customize which attribute is used as value and label by using `getOptionValue` and `getOptionLabel`, respectively.
-- If the column type is `'actions'`, you need to provide a `getActions` function that returns an array of actions available for each row (React elements).
- You can add the `showInMenu` prop on the returned React elements to signal the data grid to group these actions inside a row menu.
+```tsx
+// Without getOptionValue and getOptionLabel
+{
+ valueOptions: [
+ { value: 'BR', label: 'Brazil' },
+ { value: 'FR', label: 'France' }
+ ]
+}
- ```tsx
- {
- field: 'actions',
- type: 'actions',
- getActions: (params: GridRowParams) => [
- ,
- ,
- ]
- }
- ```
+// With getOptionValue and getOptionLabel
+{
+ getOptionValue: (value: any) => value.code,
+ getOptionLabel: (value: any) => value.name,
+ valueOptions: [
+ { code: 'BR', name: 'Brazil' },
+ { code: 'FR', name: 'France' }
+ ]
+}
+```
-{{"demo": "ColumnTypesGrid.js", "bg": "inline"}}
+:::
+
+#### Actions
+
+If the column type is `'actions'`, you need to provide a `getActions` function that returns an array of actions available for each row (React elements).
+You can add the `showInMenu` prop on the returned React elements to signal the data grid to group these actions inside a row menu.
+
+```tsx
+{
+ field: 'actions',
+ type: 'actions',
+ getActions: (params: GridRowParams) => [
+ ,
+ ,
+ ]
+}
+```
+
+By default, actions shown in the menu will close the menu on click.
+But in some cases, you might want to keep the menu open after clicking an action.
+You can achieve this by setting the `closeMenuOnClick` prop to `false`.
+
+In the following example, the "Delete" action opens a confirmation dialog and therefore needs to keep the menu mounted:
+
+{{"demo": "ActionsWithModalGrid.js", "bg": "inline"}}
### Custom column types
diff --git a/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx b/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx
index c42d8627b895e..d0efc9a2e9b42 100644
--- a/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx
+++ b/packages/grid/x-data-grid/src/components/cell/GridActionsCell.tsx
@@ -180,7 +180,7 @@ function GridActionsCell(props: GridActionsCellProps) {
if (event.key === 'Tab') {
event.preventDefault();
}
- if (['Tab', 'Enter', 'Escape'].includes(event.key)) {
+ if (['Tab', 'Escape'].includes(event.key)) {
hideMenu();
}
};
@@ -223,13 +223,7 @@ function GridActionsCell(props: GridActionsCellProps) {
)}
{menuButtons.length > 0 && (
-
+
- {menuButtons.map((button, index) => React.cloneElement(button, { key: index }))}
+ {menuButtons.map((button, index) =>
+ React.cloneElement(button, { key: index, closeMenu: hideMenu }),
+ )}
)}
diff --git a/packages/grid/x-data-grid/src/components/cell/GridActionsCellItem.tsx b/packages/grid/x-data-grid/src/components/cell/GridActionsCellItem.tsx
index 2d3d5c5307a09..3cb8f38d93b5d 100644
--- a/packages/grid/x-data-grid/src/components/cell/GridActionsCellItem.tsx
+++ b/packages/grid/x-data-grid/src/components/cell/GridActionsCellItem.tsx
@@ -12,29 +12,35 @@ export type GridActionsCellItemProps = {
component?: React.ElementType;
} & (
| ({ showInMenu?: false; icon: React.ReactElement } & IconButtonProps)
- | ({ showInMenu: true } & MenuItemProps)
+ | ({
+ showInMenu: true;
+ /**
+ * If false, the menu will not close when this item is clicked.
+ * @default true
+ */
+ closeMenuOnClick?: boolean;
+ closeMenu?: () => void;
+ } & MenuItemProps)
);
-const GridActionsCellItem = React.forwardRef(
+const GridActionsCellItem = React.forwardRef(
(props, ref) => {
- const { label, icon, showInMenu, onClick, ...other } = props;
-
const rootProps = useGridRootProps();
- const handleClick = (event: any) => {
- if (onClick) {
- onClick(event);
- }
- };
+ if (!props.showInMenu) {
+ const { label, icon, showInMenu, onClick, ...other } = props;
+
+ const handleClick = (event: React.MouseEvent) => {
+ onClick?.(event);
+ };
- if (!showInMenu) {
return (
@@ -43,8 +49,25 @@ const GridActionsCellItem = React.forwardRef) => {
+ onClick?.(event);
+ if (closeMenuOnClick) {
+ closeMenu?.();
+ }
+ };
+
return (
-