diff --git a/docs/Datagrid.md b/docs/Datagrid.md
index a5ed353e618..b3b9bd9b353 100644
--- a/docs/Datagrid.md
+++ b/docs/Datagrid.md
@@ -920,6 +920,25 @@ const PostList = () => (
);
```
+The inspector uses the field `source` (or `label` when it's a string) to display the column name. If you use non-field children (e.g. action buttons), then it's your responsibility to wrap them in a component with a `label` prop, that will be used by the inspector:
+
+```jsx
+const FieldWrapper = ({ children, label }) => children;
+const PostList = () => (
+
+
+
+
+
+
+
+
+
+
+
+);
+```
+
`` accepts the same props as ``.
## Editable Spreadsheet
diff --git a/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.spec.tsx b/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.spec.tsx
index 2f2e534a00a..e328b1e9c10 100644
--- a/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.spec.tsx
+++ b/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.spec.tsx
@@ -2,7 +2,12 @@ import * as React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import expect from 'expect';
-import { Basic, Omit, PreferenceKey } from './DatagridConfigurable.stories';
+import {
+ Basic,
+ Omit,
+ PreferenceKey,
+ LabelElement,
+} from './DatagridConfigurable.stories';
describe('', () => {
it('should render a datagrid with configurable columns', async () => {
@@ -18,7 +23,7 @@ describe('', () => {
screen.getByLabelText('Year').click();
expect(screen.queryByText('1869')).not.toBeNull();
});
- it('should accept fields with a custom title', async () => {
+ it('should accept fields with a custom label', async () => {
render();
screen.getByLabelText('Configure mode').click();
await screen.findByText('Inspector');
@@ -31,6 +36,19 @@ describe('', () => {
screen.getByLabelText('Original title').click();
expect(screen.queryByText('War and Peace')).not.toBeNull();
});
+ it('should accept fields with a label element', async () => {
+ render();
+ screen.getByLabelText('Configure mode').click();
+ await screen.findByText('Inspector');
+ fireEvent.mouseOver(screen.getByText('Leo Tolstoy'));
+ await screen.getByTitle('ra.configurable.customize').click();
+ await screen.findByText('Datagrid');
+ expect(screen.queryByText('War and Peace')).not.toBeNull();
+ screen.getByLabelText('Title').click();
+ expect(screen.queryByText('War and Peace')).toBeNull();
+ screen.getByLabelText('Title').click();
+ expect(screen.queryByText('War and Peace')).not.toBeNull();
+ });
it('should accept fields with no source', async () => {
render();
screen.getByLabelText('Configure mode').click();
diff --git a/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.stories.tsx b/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.stories.tsx
index d3c689acbea..154a5b09866 100644
--- a/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.stories.tsx
+++ b/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.stories.tsx
@@ -2,6 +2,7 @@ import * as React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { PreferencesEditorContextProvider } from 'ra-core';
import { Box } from '@mui/material';
+import { memoryStore, StoreContextProvider } from 'ra-core';
import { DatagridConfigurable } from './DatagridConfigurable';
import { Inspector, InspectorButton } from '../../preferences';
@@ -43,91 +44,100 @@ AuthorField.defaultProps = { label: 'Author' };
const theme = createTheme();
+const Wrapper = ({ children }) => (
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+);
+
export const Basic = () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
);
export const Omit = () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
export const PreferenceKey = () => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+export const LabelElement = () => (
+
+
+
+ Original title>} />
+
+
+
+
+
);
diff --git a/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.tsx b/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.tsx
index 68c0f6f2468..5b9bffb3c1c 100644
--- a/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.tsx
+++ b/packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.tsx
@@ -64,9 +64,14 @@ export const DatagridConfigurable = ({
index: String(index),
source: child.props.source,
label:
- child.props.source || child.props.label
+ child.props.label &&
+ typeof child.props.label === 'string' // this list is serializable, so we can't store ReactElement in it
? child.props.label
- : translate(
+ : child.props.source
+ ? // force the label to be the source
+ undefined
+ : // no source or label, generate a label
+ translate(
'ra.configurable.Datagrid.unlabeled',
{
column: index,