diff --git a/docs/Fields.md b/docs/Fields.md index dbb3625d25a..e1f09c8acdb 100644 --- a/docs/Fields.md +++ b/docs/Fields.md @@ -61,7 +61,7 @@ All field components accept the following props: | ---|---|---|---|--- | | `record` | Required | `Object` | - | Object containing the properties to display. ``, `` and other components inject that prop to their children | | `source` | Required | `string` | - | Name of the property to display | -| `label` | Optional | `string` | `source` | Used as a table header or an input label | +| `label` | Optional | `string | ReactElement` | `source` | Used as a table header or an input label | | `sortable` | Optional | `boolean` | `true` | When used in a `List`, should the list be sortable using the `source` attribute? Setting it to `false` disables the click handler on the column header. | | `sortBy` | Optional | `string` | `source` | When used in a `List`, specifies the actual `source` to be used for sorting when the user clicks the column header | | `className` | Optional | `string` | - | A class name (usually generated by JSS) to customize the look and feel of the field element itself | diff --git a/docs/List.md b/docs/List.md index a20e6fd667b..c591116ecaa 100644 --- a/docs/List.md +++ b/docs/List.md @@ -1217,7 +1217,7 @@ Here are all the props accepted by the component: * [`expand`](#expand) * [`isRowSelectable`](#isrowselectable) -It renders as many columns as it receives `` children. +It renders as many columns as it receives `` children. It uses the field `label` as column header (or, for fields with not `label`, the field `source`). ```jsx // in src/posts.js @@ -1546,7 +1546,7 @@ For this kind of use case, you need to use a [custom datagrid body component](#b ### Performance -when displaying large pages of data, you might experience some performance issues. +When displaying large pages of data, you might experience some performance issues. This is mostly due to the fact that we iterate over the `` children and clone them. In such cases, you can opt-in for an optimized version of the `` by setting its `optimized` prop to `true`. diff --git a/packages/ra-core/src/util/FieldTitle.tsx b/packages/ra-core/src/util/FieldTitle.tsx index 1ad53e016bf..4275fb706c2 100644 --- a/packages/ra-core/src/util/FieldTitle.tsx +++ b/packages/ra-core/src/util/FieldTitle.tsx @@ -1,4 +1,4 @@ -import React, { FunctionComponent } from 'react'; +import React, { FunctionComponent, ReactElement } from 'react'; import pure from 'recompose/pure'; import useTranslate from '../i18n/useTranslate'; @@ -8,7 +8,7 @@ interface Props { isRequired?: boolean; resource?: string; source?: string; - label?: string; + label?: string | ReactElement; } export const FieldTitle: FunctionComponent = ({ @@ -18,10 +18,17 @@ export const FieldTitle: FunctionComponent = ({ isRequired, }) => { const translate = useTranslate(); + if (label && typeof label !== 'string') { + return label; + } return ( {translate( - ...getFieldLabelTranslationArgs({ label, resource, source }) + ...getFieldLabelTranslationArgs({ + label: label as string, + resource, + source, + }) )} {isRequired && ' *'} diff --git a/packages/ra-ui-materialui/src/field/types.ts b/packages/ra-ui-materialui/src/field/types.ts index f7787ea2f91..5dd38d2a99f 100644 --- a/packages/ra-ui-materialui/src/field/types.ts +++ b/packages/ra-ui-materialui/src/field/types.ts @@ -1,3 +1,4 @@ +import { ReactElement } from 'react'; import { Record } from 'ra-core'; import PropTypes from 'prop-types'; @@ -8,7 +9,7 @@ export interface FieldProps { sortBy?: string; sortByOrder?: SortOrder; source?: string; - label?: string; + label?: string | ReactElement; sortable?: boolean; className?: string; cellClassName?: string; @@ -28,7 +29,7 @@ export const fieldPropTypes = { sortBy: PropTypes.string, sortByOrder: PropTypes.oneOf(['ASC', 'DESC']), source: PropTypes.string, - label: PropTypes.string, + label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), sortable: PropTypes.bool, className: PropTypes.string, cellClassName: PropTypes.string, diff --git a/packages/ra-ui-materialui/src/input/Labeled.tsx b/packages/ra-ui-materialui/src/input/Labeled.tsx index 5d1b4668aee..91dc2f16fce 100644 --- a/packages/ra-ui-materialui/src/input/Labeled.tsx +++ b/packages/ra-ui-materialui/src/input/Labeled.tsx @@ -34,7 +34,7 @@ interface Props { id: string; input: any; isRequired: boolean; - label?: string; + label?: string | ReactElement; meta: any; resource: string; source: string; @@ -119,7 +119,7 @@ Labeled.propTypes = { id: PropTypes.string, input: PropTypes.object, isRequired: PropTypes.bool, - label: PropTypes.string, + label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), meta: PropTypes.object, onChange: PropTypes.func, record: PropTypes.object, diff --git a/packages/ra-ui-materialui/src/list/DatagridHeaderCell.spec.js b/packages/ra-ui-materialui/src/list/DatagridHeaderCell.spec.js index a89dc98f813..56f4822b177 100644 --- a/packages/ra-ui-materialui/src/list/DatagridHeaderCell.spec.js +++ b/packages/ra-ui-materialui/src/list/DatagridHeaderCell.spec.js @@ -7,6 +7,25 @@ import { DatagridHeaderCell } from './DatagridHeaderCell'; describe('', () => { afterEach(cleanup); + it('should accept a React element as Field label', () => { + const Label = () => <>Label; + const Field = () =>
; + const { getByText } = render( + + + + } />} + updateSort={() => true} + /> + + +
+ ); + expect(getByText('Label')).toBeDefined(); + }); + describe('sorting on a column', () => { const Field = () =>
; Field.defaultProps = {